# Walls and Gates

- slug: walls-and-gates
- difficulty: Medium

You are given an `m x n` grid `rooms` initialized with these three possible values.

*   `-1` A wall or an obstacle.
*   `0` A gate.
*   `INF` Infinity means an empty room. We use the value `231 - 1 = 2147483647` to represent `INF` as you may assume that the distance to a gate is less than `2147483647`.

Fill each empty room with the distance to _its nearest gate_. If it is impossible to reach a gate, it should be filled with `INF`.

**Example 1:**

**Input:** rooms = \[\[2147483647,-1,0,2147483647\],\[2147483647,2147483647,2147483647,-1\],\[2147483647,-1,2147483647,-1\],\[0,-1,2147483647,2147483647\]\]
**Output:** \[\[3,-1,0,1\],\[2,2,1,-1\],\[1,-1,2,-1\],\[0,-1,3,4\]\]

**Example 2:**

**Input:** rooms = \[\[-1\]\]
**Output:** \[\[-1\]\]

**Constraints:**

*   `m == rooms.length`
*   `n == rooms[i].length`
*   `1 <= m, n <= 250`
*   `rooms[i][j]` is `-1`, `0`, or `231 - 1`.

## A solution in Java

```java
import java.util.Queue;
import java.util.LinkedList;

public void wallsAndGates(int[][] rooms) {
    int m = rooms.length;
    int n = rooms[0].length;
    Queue<int[]> q = new LinkedList<>();
    int INF = 2147483647;

    for(int i = 0; i < m; i++) {
        for(int j = 0; j < n; j++) {
            if(rooms[i][j] == 0) {
                q.offer(new int[]{i, j});
            }
        }
    }

    int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

    while(!q.isEmpty()) {
        int[] cur = q.poll();
        int i = cur[0];
        int j = cur[1];

        for(int[] d : directions) {
            int ni = i + d[0];
            int nj = j + d[1];

            if(ni >= 0 && ni < m && nj >= 0 && nj < n && rooms[ni][nj] == INF) {
                rooms[ni][nj] = rooms[i][j] + 1;
                q.offer(new int[]{ni, nj});
            }
        }
    }
}
```
The algorithm uses BFS (Breadth-First Search) to find the shortest distances from empty rooms to gates. We first create a queue `q` and add all the gates' coordinates to it. Then, we create an array `directions` containing possible moves (up, down, left, right).

While the queue is not empty, we loop through all the gates in the queue, and for each gate, we explore its neighbors (up, down, left, right) and check if they are empty rooms. If they are, we update their distance to be 1 more than the current gate's distance, and add these neighbors to the queue. Once a room's distance is updated, it will not be updated again because that's the shortest distance found. The process continues until all reachable empty rooms have their distances updated.

This algorithm operates in O(m*n) time complexity, where m and n are the dimensions of the grid rooms, since each cell is visited once.

## A solution in C++

```cpp
#include <vector>
#include <queue>
using namespace std;

void wallsAndGates(vector<vector<int>>& rooms) {
    const int INF = 2147483647;
    int m = rooms.size();
    int n = rooms[0].size();
    queue<pair<int, int>> q;

    for(int i = 0; i < m; i++) {
        for(int j = 0; j < n; j++) {
            if(rooms[i][j] == 0) {
                q.push(make_pair(i, j));
            }
        }
    }

    int directions[][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};

    while(!q.empty()) {
        int i = q.front().first;
        int j = q.front().second;
        q.pop();

        for(auto d : directions) {
            int ni = i + d[0];
            int nj = j + d[1];

            if(ni >= 0 && ni < m && nj >= 0 && nj < n && rooms[ni][nj] == INF) {
                rooms[ni][nj] = rooms[i][j] + 1;
                q.push(make_pair(ni, nj));
            }
        }
    }
}
```
The algorithm uses BFS (Breadth-First Search) to find the shortest distances from empty rooms to gates. We first create a queue `q` and add all the gates' coordinates to it. Then, we create an array `directions` containing possible moves (up, down, left, right).

While the queue is not empty, we loop through all the gates in the queue, and for each gate, we explore its neighbors (up, down, left, right) and check if they are empty rooms. If they are, we update their distance to be 1 more than the current gate's distance, and add these neighbors to the queue. Once a room's distance is updated, it will not be updated again because that's the shortest distance found. The process continues until all reachable empty rooms have their distances updated.

This algorithm operates in O(m*n) time complexity, where m and n are the dimensions of the grid rooms, since each cell is visited once.

## A solution in Python

```python
from collections import deque

def wallsAndGates(rooms):
    m, n = len(rooms), len(rooms[0])
    q = deque()
    INF = 2147483647

    for i in range(m):
        for j in range(n):
            if rooms[i][j] == 0:
                q.append((i, j))

    directions = [(0, 1), (0, -1), (1, 0), (-1, 0)]

    while q:
        i, j = q.popleft()

        for d in directions:
            ni, nj = i + d[0], j + d[1]

            if 0 <= ni < m and 0 <= nj < n and rooms[ni][nj] == INF:
                rooms[ni][nj] = rooms[i][j] + 1
                q.append((ni, nj))

```
The algorithm uses BFS (Breadth-First Search) to find the shortest distances from empty rooms to gates. We first create a queue `q` and add all the gates' coordinates to it. Then, we create an array `directions` containing possible moves (up, down, left, right).

While the queue is not empty, we loop through all the gates in the queue, and for each gate, we explore its neighbors (up, down, left, right) and check if they are empty rooms. If they are, we update their distance to be 1 more than the current gate's distance, and add these neighbors to the queue. Once a room's distance is updated, it will not be updated again because that's the shortest distance found. The process continues until all reachable empty rooms have their distances updated.

This algorithm operates in O(m*n) time complexity, where m and n are the dimensions of the grid rooms, since each cell is visited once.

## A solution in Javascript

```javascript
function wallsAndGates(rooms) {
    const m = rooms.length;
    const n = rooms[0].length;
    const q = [];
    const INF = 2147483647;

    for (let i = 0; i < m; i++) {
        for (let j = 0; j < n; j++) {
            if (rooms[i][j] === 0) {
                q.push([i, j]);
            }
        }
    }

    const directions = [
        [0, 1],
        [0, -1],
        [1, 0],
        [-1, 0]
    ];

    while (q.length) {
        const [i, j] = q.shift();

        directions.forEach(([di, dj]) => {
            const ni = i + di;
            const nj = j + dj;

            if (ni >= 0 && ni < m && nj >= 0 && nj < n && rooms[ni][nj] === INF) {
                rooms[ni][nj] = rooms[i][j] + 1;
                q.push([ni, nj]);
            }
        });
    }
}
```
The algorithm uses BFS (Breadth-First Search) to find the shortest distances from empty rooms to gates. We first create a queue `q` and add all the gates' coordinates to it. Then, we create an array `directions` containing possible moves (up, down, left, right).

While the queue is not empty, we loop through all the gates in the queue, and for each gate, we explore its neighbors (up, down, left, right) and check if they are empty rooms. If they are, we update their distance to be 1 more than the current gate's distance, and add these neighbors to the queue. Once a room's distance is updated, it will not be updated again because that's the shortest distance found. The process continues until all reachable empty rooms have their distances updated.

This algorithm operates in O(m*n) time complexity, where m and n are the dimensions of the grid rooms, since each cell is visited once.


# Find the Duplicate Number

- slug: find-the-duplicate-number
- difficulty: Medium

Given an array of integers `nums` containing `n + 1` integers where each integer is in the range `[1, n]` inclusive.

There is only **one repeated number** in `nums`, return _this repeated number_.

You must solve the problem **without** modifying the array `nums` and uses only constant extra space.

**Example 1:**

**Input:** nums = \[1,3,4,2,2\]
**Output:** 2

**Example 2:**

**Input:** nums = \[3,1,3,4,2\]
**Output:** 3

**Constraints:**

*   `1 <= n <= 105`
*   `nums.length == n + 1`
*   `1 <= nums[i] <= n`
*   All the integers in `nums` appear only **once** except for **precisely one integer** which appears **two or more** times.

**Follow up:**

*   How can we prove that at least one duplicate number must exist in `nums`?
*   Can you solve the problem in linear runtime complexity?

## A solution in Java

```java
public int findDuplicate(int[] nums) {
    int slow = nums[0];
    int fast = nums[0];

    do {
        slow = nums[slow];
        fast = nums[nums[fast]];
    } while (slow != fast);

    slow = nums[0];

    while (slow != fast) {
        slow = nums[slow];
        fast = nums[fast];
    }

    return slow;
}
```
The algorithm is based on Floyd's Tortoise and Hare (Cycle Detection) algorithm. We treat the given array as a linked list where the value at each index is treated as the pointer to the next node in the list.

1. Initialize two pointers, `slow` and `fast`, both initially pointing to the first element of the array.
2. Loop through the array, updating `slow` to point to the next element and `fast` to point to the element after the next element, until they meet.
3. Reset `slow` to the first element of the array and keep `fast` at the meeting point.
4. Loop through the array, updating `slow` and `fast` to point to the next element until they meet again. This meeting point is the duplicate number.

This algorithm has a time complexity of O(n) and a space complexity of O(1).

## A solution in C++

```cpp
int findDuplicate(vector<int>& nums) {
    int slow = nums[0];
    int fast = nums[0];

    do {
        slow = nums[slow];
        fast = nums[nums[fast]];
    } while (slow != fast);

    slow = nums[0];

    while (slow != fast) {
        slow = nums[slow];
        fast = nums[fast];
    }

    return slow;
}
```
The algorithm is based on Floyd's Tortoise and Hare (Cycle Detection) algorithm. We treat the given array as a linked list where the value at each index is treated as the pointer to the next node in the list.

1. Initialize two pointers, `slow` and `fast`, both initially pointing to the first element of the array.
2. Loop through the array, updating `slow` to point to the next element and `fast` to point to the element after the next element, until they meet.
3. Reset `slow` to the first element of the array and keep `fast` at the meeting point.
4. Loop through the array, updating `slow` and `fast` to point to the next element until they meet again. This meeting point is the duplicate number.

This algorithm has a time complexity of O(n) and a space complexity of O(1).

## A solution in Python

```python
def findDuplicate(nums):
    slow = nums[0]
    fast = nums[0]

    while True:
        slow = nums[slow]
        fast = nums[nums[fast]]
        if slow == fast:
            break

    slow = nums[0]

    while slow != fast:
        slow = nums[slow]
        fast = nums[fast]

    return slow
```
The algorithm is based on Floyd's Tortoise and Hare (Cycle Detection) algorithm. We treat the given array as a linked list where the value at each index is treated as the pointer to the next node in the list.

1. Initialize two pointers, `slow` and `fast`, both initially pointing to the first element of the array.
2. Loop through the array, updating `slow` to point to the next element and `fast` to point to the element after the next element, until they meet.
3. Reset `slow` to the first element of the array and keep `fast` at the meeting point.
4. Loop through the array, updating `slow` and `fast` to point to the next element until they meet again. This meeting point is the duplicate number.

This algorithm has a time complexity of O(n) and a space complexity of O(1).

## A solution in Javascript

```javascript
function findDuplicate(nums) {
    let slow = nums[0];
    let fast = nums[0];

    do {
        slow = nums[slow];
        fast = nums[nums[fast]];
    } while (slow !== fast);

    slow = nums[0];

    while (slow !== fast) {
        slow = nums[slow];
        fast = nums[fast];
    }

    return slow;
}
```
The algorithm is based on Floyd's Tortoise and Hare (Cycle Detection) algorithm. We treat the given array as a linked list where the value at each index is treated as the pointer to the next node in the list.

1. Initialize two pointers, `slow` and `fast`, both initially pointing to the first element of the array.
2. Loop through the array, updating `slow` to point to the next element and `fast` to point to the element after the next element, until they meet.
3. Reset `slow` to the first element of the array and keep `fast` at the meeting point.
4. Loop through the array, updating `slow` and `fast` to point to the next element until they meet again. This meeting point is the duplicate number.

This algorithm has a time complexity of O(n) and a space complexity of O(1).


# Unique Word Abbreviation

- slug: unique-word-abbreviation
- difficulty: Medium

The **abbreviation** of a word is a concatenation of its first letter, the number of characters between the first and last letter, and its last letter. If a word has only two characters, then it is an **abbreviation** of itself.

For example:

*   `dog --> d1g` because there is one letter between the first letter `'d'` and the last letter `'g'`.
*   `internationalization --> i18n` because there are 18 letters between the first letter `'i'` and the last letter `'n'`.
*   `it --> it` because any word with only two characters is an **abbreviation** of itself.

Implement the `ValidWordAbbr` class:

*   `ValidWordAbbr(String[] dictionary)` Initializes the object with a `dictionary` of words.
*   `boolean isUnique(string word)` Returns `true` if **either** of the following conditions are met (otherwise returns `false`):
    *   There is no word in `dictionary` whose **abbreviation** is equal to `word`'s **abbreviation**.
    *   For any word in `dictionary` whose **abbreviation** is equal to `word`'s **abbreviation**, that word and `word` are **the same**.

**Example 1:**

**Input**
\[ "ValidWordAbbr ",  "isUnique ",  "isUnique ",  "isUnique ",  "isUnique ",  "isUnique "\]
\[\[\[ "deer ",  "door ",  "cake ",  "card "\]\], \[ "dear "\], \[ "cart "\], \[ "cane "\], \[ "make "\], \[ "cake "\]\]
**Output**
\[null, false, true, false, true, true\]

**Explanation**
ValidWordAbbr validWordAbbr = new ValidWordAbbr(\[ "deer ",  "door ",  "cake ",  "card "\]);
validWordAbbr.isUnique( "dear "); // return false, dictionary word  "deer " and word  "dear " have the same abbreviation  "d2r " but are not the same.
validWordAbbr.isUnique( "cart "); // return true, no words in the dictionary have the abbreviation  "c2t ".
validWordAbbr.isUnique( "cane "); // return false, dictionary word  "cake " and word  "cane " have the same abbreviation   "c2e " but are not the same.
validWordAbbr.isUnique( "make "); // return true, no words in the dictionary have the abbreviation  "m2e ".
validWordAbbr.isUnique( "cake "); // return true, because  "cake " is already in the dictionary and no other word in the dictionary has  "c2e " abbreviation.

**Constraints:**

*   `1 <= dictionary.length <= 3 * 104`
*   `1 <= dictionary[i].length <= 20`
*   `dictionary[i]` consists of lowercase English letters.
*   `1 <= word.length <= 20`
*   `word` consists of lowercase English letters.
*   At most `5000` calls will be made to `isUnique`.

## A solution in Java

```java
import java.util.*;

class ValidWordAbbr {
    private Map<String, Set<String>> wordMap;

    public ValidWordAbbr(String[] dictionary) {
        wordMap = new HashMap<>();
        for (String word : dictionary) {
            String abbr = getAbbreviation(word);
            wordMap.putIfAbsent(abbr, new HashSet<>());
            wordMap.get(abbr).add(word);
        }
    }

    public boolean isUnique(String word) {
        String abbr = getAbbreviation(word);
        Set<String> abbrGroup = wordMap.get(abbr);
        return abbrGroup == null || (abbrGroup.size() == 1 && abbrGroup.contains(word));
    }

    private String getAbbreviation(String word) {
        int n = word.length();
        return n <= 2 ? word : word.charAt(0) + Integer.toString(n - 2) + word.charAt(n - 1);
    }
}
```
The algorithm first initializes the class by storing the words into a hash map with their abbreviations as keys and a set containing the words with this abbreviation as the value. This allows for efficient lookups and eliminates duplicates in the `dictionary`.

For the `isUnique` function, the algorithm first gets the abbreviation of the `word`. Then, it checks whether the abbreviation is not present in the hash map or whether the abbreviation is present with only one word (the same as the input word) in the set. If either of these conditions is met, the function returns `true`. Otherwise, it returns `false`.

The `get_abbreviation` function returns the abbreviated version of a given `word`. If the length of the `word` is less than or equal to 2, the function returns the `word` itself; otherwise, it returns the first character, the number of characters between the first and last characters, and the last character of the `word` as a string.

## A solution in C++

```cpp
#include <string>
#include <unordered_map>

class ValidWordAbbr {
public:
    ValidWordAbbr(vector<string>& dictionary) {
        for (auto& word : dictionary) {
            string abbr = get_abbreviation(word);
            word_map[abbr].insert(word);
        }
    }

    bool isUnique(string word) {
        string abbr = get_abbreviation(word);
        auto abbr_group = word_map.find(abbr);
        return abbr_group == word_map.end() || (abbr_group->second.size() == 1 && abbr_group->second.count(word));
    }

private:
    unordered_map<string, unordered_set<string>> word_map;

    string get_abbreviation(const string& word) {
        int n = word.size();
        return n <= 2 ? word : word.front() + to_string(n - 2) + word.back();
    }
};
```
The algorithm first initializes the class by storing the words into a hash map with their abbreviations as keys and a set containing the words with this abbreviation as the value. This allows for efficient lookups and eliminates duplicates in the `dictionary`.

For the `isUnique` function, the algorithm first gets the abbreviation of the `word`. Then, it checks whether the abbreviation is not present in the hash map or whether the abbreviation is present with only one word (the same as the input word) in the set. If either of these conditions is met, the function returns `true`. Otherwise, it returns `false`.

The `get_abbreviation` function returns the abbreviated version of a given `word`. If the length of the `word` is less than or equal to 2, the function returns the `word` itself; otherwise, it returns the first character, the number of characters between the first and last characters, and the last character of the `word` as a string.

## A solution in Python

```python
class ValidWordAbbr:

    def __init__(self, dictionary):
        self.word_map = {}
        for word in dictionary:
            abbr = self.get_abbreviation(word)
            if abbr not in self.word_map:
                self.word_map[abbr] = {word}
            else:
                self.word_map[abbr].add(word)

    def isUnique(self, word):
        abbr = self.get_abbreviation(word)
        abbr_group = self.word_map.get(abbr, set())
        return len(abbr_group) == 0 or (len(abbr_group) == 1 and word in abbr_group)

    def get_abbreviation(self, word):
        n = len(word)
        return word if n <= 2 else word[0] + str(n - 2) + word[-1]
```
The algorithm first initializes the class by storing the words into a hash map with their abbreviations as keys and a set containing the words with this abbreviation as the value. This allows for efficient lookups and eliminates duplicates in the `dictionary`.

For the `isUnique` function, the algorithm first gets the abbreviation of the `word`. Then, it checks whether the abbreviation is not present in the hash map or whether the abbreviation is present with only one word (the same as the input word) in the set. If either of these conditions is met, the function returns `true`. Otherwise, it returns `false`.

The `get_abbreviation` function returns the abbreviated version of a given `word`. If the length of the `word` is less than or equal to 2, the function returns the `word` itself; otherwise, it returns the first character, the number of characters between the first and last characters, and the last character of the `word` as a string.

## A solution in Javascript

```javascript
class ValidWordAbbr {
    constructor(dictionary) {
        this.wordMap = new Map();
        for (let word of dictionary) {
            let abbr = this.getAbbreviation(word);
            if (!this.wordMap.has(abbr)) {
                this.wordMap.set(abbr, new Set([word]));
            } else {
                this.wordMap.get(abbr).add(word);
            }
        }
    }

    isUnique(word) {
        let abbr = this.getAbbreviation(word);
        let abbrGroup = this.wordMap.get(abbr) || new Set();
        return abbrGroup.size === 0 || (abbrGroup.size === 1 && abbrGroup.has(word));
    }

    getAbbreviation(word) {
        let n = word.length;
        return n <= 2 ? word : word[0] + (n - 2) + word[n - 1];
    }
}
```
The algorithm first initializes the class by storing the words into a hash map with their abbreviations as keys and a set containing the words with this abbreviation as the value. This allows for efficient lookups and eliminates duplicates in the `dictionary`.

For the `isUnique` function, the algorithm first gets the abbreviation of the `word`. Then, it checks whether the abbreviation is not present in the hash map or whether the abbreviation is present with only one word (the same as the input word) in the set. If either of these conditions is met, the function returns `true`. Otherwise, it returns `false`.

The `get_abbreviation` function returns the abbreviated version of a given `word`. If the length of the `word` is less than or equal to 2, the function returns the `word` itself; otherwise, it returns the first character, the number of characters between the first and last characters, and the last character of the `word` as a string.


# Game of Life

- slug: game-of-life
- difficulty: Medium

According to [Wikipedia's article](https://en.wikipedia.org/wiki/Conway%27s_Game_of_Life): "The **Game of Life**, also known simply as **Life**, is a cellular automaton devised by the British mathematician John Horton Conway in 1970. "

The board is made up of an `m x n` grid of cells, where each cell has an initial state: **live** (represented by a `1`) or **dead** (represented by a `0`). Each cell interacts with its [eight neighbors](https://en.wikipedia.org/wiki/Moore_neighborhood) (horizontal, vertical, diagonal) using the following four rules (taken from the above Wikipedia article):

1.  Any live cell with fewer than two live neighbors dies as if caused by under-population.
2.  Any live cell with two or three live neighbors lives on to the next generation.
3.  Any live cell with more than three live neighbors dies, as if by over-population.
4.  Any dead cell with exactly three live neighbors becomes a live cell, as if by reproduction.

The next state is created by applying the above rules simultaneously to every cell in the current state, where births and deaths occur simultaneously. Given the current state of the `m x n` grid `board`, return _the next state_.

**Example 1:**

**Input:** board = \[\[0,1,0\],\[0,0,1\],\[1,1,1\],\[0,0,0\]\]
**Output:** \[\[0,0,0\],\[1,0,1\],\[0,1,1\],\[0,1,0\]\]

**Example 2:**

**Input:** board = \[\[1,1\],\[1,0\]\]
**Output:** \[\[1,1\],\[1,1\]\]

**Constraints:**

*   `m == board.length`
*   `n == board[i].length`
*   `1 <= m, n <= 25`
*   `board[i][j]` is `0` or `1`.

**Follow up:**

*   Could you solve it in-place? Remember that the board needs to be updated simultaneously: You cannot update some cells first and then use their updated values to update other cells.
*   In this question, we represent the board using a 2D array. In principle, the board is infinite, which would cause problems when the active area encroaches upon the border of the array (i.e., live cells reach the border). How would you address these problems?

## A solution in Java

```java
public int[][] gameOfLife(int[][] board) {
    int m = board.length;
    int n = board[0].length;
    int[][] result = new int[m][n];
    int[][] dirs = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};

    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            int liveNeighbors = 0;

            for (int[] dir : dirs) {
                int newRow = i + dir[0];
                int newCol = j + dir[1];

                if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && board[newRow][newCol] == 1) {
                    liveNeighbors++;
                }
            }

            if (board[i][j] == 1 && (liveNeighbors == 2 || liveNeighbors == 3)) {
                result[i][j] = 1;
            } else if (board[i][j] == 0 && liveNeighbors == 3) {
                result[i][j] = 1;
            }
        }
    }

    return result;
}
```
Create a new board called `result` with the same dimensions as the input board. For each cell in the input board, count the live neighbors (the 8 neighboring cells). Then apply the following rules:
1. Any live cell with two or three live neighbors survives.
2. Any dead cell with exactly three live neighbors becomes a live cell.
3. All other live cells die and all other dead cells stay dead.

To count live neighbors, iterate through a predefined list of relative coordinates `dirs` representing the eight neighboring cells. For each neighboring coordinate, check if it is inside the grid, and if the corresponding cell in the input board is live. If so, increment the counter of live neighbors.

Finally, update the cell in the result board using the rules.

## A solution in C++

```cpp
#include <vector>

std::vector<std::vector<int>> gameOfLife(std::vector<std::vector<int>>& board) {
    int m = board.size();
    int n = board[0].size();
    std::vector<std::vector<int>> result(m, std::vector<int>(n, 0));

    std::vector<std::vector<int>> dirs = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 1}, {1, -1}, {1, 0}, {1, 1}};

    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            int liveNeighbors = 0;

            for (std::vector<int> dir : dirs) {
                int newRow = i + dir[0];
                int newCol = j + dir[1];

                if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && board[newRow][newCol] == 1) {
                    liveNeighbors++;
                }
            }

            if (board[i][j] == 1 && (liveNeighbors == 2 || liveNeighbors == 3)) {
                result[i][j] = 1;
            } else if (board[i][j] == 0 && liveNeighbors == 3) {
                result[i][j] = 1;
            }
        }
    }

    return result;
}
```
Create a new board called `result` with the same dimensions as the input board. For each cell in the input board, count the live neighbors (the 8 neighboring cells). Then apply the following rules:
1. Any live cell with two or three live neighbors survives.
2. Any dead cell with exactly three live neighbors becomes a live cell.
3. All other live cells die and all other dead cells stay dead.

To count live neighbors, iterate through a predefined list of relative coordinates `dirs` representing the eight neighboring cells. For each neighboring coordinate, check if it is inside the grid, and if the corresponding cell in the input board is live. If so, increment the counter of live neighbors.

Finally, update the cell in the result board using the rules.

## A solution in Python

```python
def gameOfLife(board):
    m, n = len(board), len(board[0])
    result = [[0] * n for _ in range(m)]
    dirs = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]]

    for i in range(m):
        for j in range(n):
            liveNeighbors = 0

            for dir in dirs:
                newRow = i + dir[0]
                newCol = j + dir[1]

                if newRow >= 0 and newRow < m and newCol >= 0 and newCol < n and board[newRow][newCol] == 1:
                    liveNeighbors += 1

            if board[i][j] == 1 and (liveNeighbors == 2 or liveNeighbors == 3):
                result[i][j] = 1
            elif board[i][j] == 0 and liveNeighbors == 3:
                result[i][j] = 1

    return result
```
Create a new board called `result` with the same dimensions as the input board. For each cell in the input board, count the live neighbors (the 8 neighboring cells). Then apply the following rules:
1. Any live cell with two or three live neighbors survives.
2. Any dead cell with exactly three live neighbors becomes a live cell.
3. All other live cells die and all other dead cells stay dead.

To count live neighbors, iterate through a predefined list of relative coordinates `dirs` representing the eight neighboring cells. For each neighboring coordinate, check if it is inside the grid, and if the corresponding cell in the input board is live. If so, increment the counter of live neighbors.

Finally, update the cell in the result board using the rules.

## A solution in Javascript

```javascript
function gameOfLife(board) {
    let m = board.length;
    let n = board[0].length;
    let result = new Array(m).fill(0).map(() => new Array(n).fill(0));
    let dirs = [[-1, -1], [-1, 0], [-1, 1], [0, -1], [0, 1], [1, -1], [1, 0], [1, 1]];

    for (let i = 0; i < m; i++) {
        for (let j = 0; j < n; j++) {
            let liveNeighbors = 0;

            for (let dir of dirs) {
                let newRow = i + dir[0];
                let newCol = j + dir[1];

                if (newRow >= 0 && newRow < m && newCol >= 0 && newCol < n && board[newRow][newCol] === 1) {
                    liveNeighbors++;
                }
            }

            if (board[i][j] === 1 && (liveNeighbors === 2 || liveNeighbors === 3)) {
                result[i][j] = 1;
            } else if (board[i][j] === 0 && liveNeighbors === 3) {
                result[i][j] = 1;
            }
        }
    }

    return result;
}
```
Create a new board called `result` with the same dimensions as the input board. For each cell in the input board, count the live neighbors (the 8 neighboring cells). Then apply the following rules:
1. Any live cell with two or three live neighbors survives.
2. Any dead cell with exactly three live neighbors becomes a live cell.
3. All other live cells die and all other dead cells stay dead.

To count live neighbors, iterate through a predefined list of relative coordinates `dirs` representing the eight neighboring cells. For each neighboring coordinate, check if it is inside the grid, and if the corresponding cell in the input board is live. If so, increment the counter of live neighbors.

Finally, update the cell in the result board using the rules.


# Word Pattern

- slug: word-pattern
- difficulty: Easy

Given a `pattern` and a string `s`, find if `s` follows the same pattern.

Here **follow** means a full match, such that there is a bijection between a letter in `pattern` and a **non-empty** word in `s`.

**Example 1:**

**Input:** pattern =  "abba ", s =  "dog cat cat dog "
**Output:** true

**Example 2:**

**Input:** pattern =  "abba ", s =  "dog cat cat fish "
**Output:** false

**Example 3:**

**Input:** pattern =  "aaaa ", s =  "dog cat cat dog "
**Output:** false

**Constraints:**

*   `1 <= pattern.length <= 300`
*   `pattern` contains only lower-case English letters.
*   `1 <= s.length <= 3000`
*   `s` contains only lowercase English letters and spaces `' '`.
*   `s` **does not contain** any leading or trailing spaces.
*   All the words in `s` are separated by a **single space**.

## A solution in Java

```java
import java.util.HashMap;
import java.util.Map;

public boolean wordPattern(String pattern, String s) {
    String[] words = s.split(" ");
    if (pattern.length() != words.length) return false;

    Map<Character, String> charMap = new HashMap<>();
    Map<String, Character> wordMap = new HashMap<>();

    for (int i = 0; i < pattern.length(); i++) {
        char c = pattern.charAt(i);
        String word = words[i];
        if (!charMap.containsKey(c) && !wordMap.containsKey(word)) {
            charMap.put(c, word);
            wordMap.put(word, c);
        } else {
            if (!word.equals(charMap.get(c)) || c != wordMap.get(word)) return false;
        }
    }

    return true;
}
```
1. First, split the string 's' into words array based on the space-delimited words.
2. Check if the length of the pattern and words array is the same, otherwise return false.
3. Create two maps (hash tables/dictionaries) - one for storing the mapping from a pattern character to a word, and the other for mapping from a word to a pattern character.
4. Iterate through the pattern and the words array simultaneously using a loop.
5. If a pattern character and word are not in the respective maps, save the corresponding mapping in both maps.
6. If they exist, compare the mappings; if they differ, immediately return false.
7. After the loop is completed, if there is no mismatch, return true.

## A solution in C++

```cpp
#include <string>
#include <unordered_map>
#include <sstream>
using namespace std;

bool wordPattern(string pattern, string s) {
    unordered_map<char, string> char_map;
    unordered_map<string, char> word_map;
    stringstream ss(s);

    int i = 0;
    for (string word; ss >> word; ++i) {
        if (i == pattern.size()) return false;
        char c = pattern[i];
        if (char_map.count(c) == 0 && word_map.count(word) == 0) {
            char_map[c] = word;
            word_map[word] = c;
        } else {
            if (char_map[c] != word || word_map[word] != c) return false;
        }
    }

    return i == pattern.size();
}
```
1. First, split the string 's' into words array based on the space-delimited words.
2. Check if the length of the pattern and words array is the same, otherwise return false.
3. Create two maps (hash tables/dictionaries) - one for storing the mapping from a pattern character to a word, and the other for mapping from a word to a pattern character.
4. Iterate through the pattern and the words array simultaneously using a loop.
5. If a pattern character and word are not in the respective maps, save the corresponding mapping in both maps.
6. If they exist, compare the mappings; if they differ, immediately return false.
7. After the loop is completed, if there is no mismatch, return true.

## A solution in Python

```python
def word_pattern(pattern, s):
    words = s.split()
    if len(pattern) != len(words):
        return False

    char_map, word_map = {}, {}
    for c, word in zip(pattern, words):
        if c not in char_map and word not in word_map:
            char_map[c] = word
            word_map[word] = c
        else:
            if char_map.get(c) != word or word_map.get(word) != c:
                return False

    return True
```
1. First, split the string 's' into words array based on the space-delimited words.
2. Check if the length of the pattern and words array is the same, otherwise return false.
3. Create two maps (hash tables/dictionaries) - one for storing the mapping from a pattern character to a word, and the other for mapping from a word to a pattern character.
4. Iterate through the pattern and the words array simultaneously using a loop.
5. If a pattern character and word are not in the respective maps, save the corresponding mapping in both maps.
6. If they exist, compare the mappings; if they differ, immediately return false.
7. After the loop is completed, if there is no mismatch, return true.

## A solution in Javascript

```javascript
function wordPattern(pattern, s) {
    const words = s.split(' ');
    if (pattern.length !== words.length) return false;

    const charMap = new Map();
    const wordMap = new Map();

    for (let i = 0; i < pattern.length; i++) {
        const c = pattern[i];
        const word = words[i];
        if (!charMap.has(c) && !wordMap.has(word)) {
            charMap.set(c, word);
            wordMap.set(word, c);
        } else {
            if (charMap.get(c) !== word || wordMap.get(word) !== c) return false;
        }
    }

    return true;
}
```
1. First, split the string 's' into words array based on the space-delimited words.
2. Check if the length of the pattern and words array is the same, otherwise return false.
3. Create two maps (hash tables/dictionaries) - one for storing the mapping from a pattern character to a word, and the other for mapping from a word to a pattern character.
4. Iterate through the pattern and the words array simultaneously using a loop.
5. If a pattern character and word are not in the respective maps, save the corresponding mapping in both maps.
6. If they exist, compare the mappings; if they differ, immediately return false.
7. After the loop is completed, if there is no mismatch, return true.


# Word Pattern II

- slug: word-pattern-ii
- difficulty: Medium

Given a `pattern` and a string `s`, return `true` _if_ `s` _**matches** the_ `pattern`_._

A string `s` **matches** a `pattern` if there is some **bijective mapping** of single characters to strings such that if each character in `pattern` is replaced by the string it maps to, then the resulting string is `s`. A **bijective mapping** means that no two characters map to the same string, and no character maps to two different strings.

**Example 1:**

**Input:** pattern =  "abab ", s =  "redblueredblue "
**Output:** true
**Explanation:** One possible mapping is as follows:
'a' ->  "red "
'b' ->  "blue "

**Example 2:**

**Input:** pattern =  "aaaa ", s =  "asdasdasdasd "
**Output:** true
**Explanation:** One possible mapping is as follows:
'a' ->  "asd "

**Example 3:**

**Input:** pattern =  "aabb ", s =  "xyzabcxzyabc "
**Output:** false

**Constraints:**

*   `1 <= pattern.length, s.length <= 20`
*   `pattern` and `s` consist of only lowercase English letters.

## A solution in Java

```java
public boolean wordPatternMatch(String pattern, String s) {
    Map<Character, String> patternMap = new HashMap<>();
    Set<String> words = new HashSet<>();
    return backtrack(pattern, 0, s, 0, patternMap, words);
}

private boolean backtrack(String pattern, int pIndex, String s, int sIndex, Map<Character, String> patternMap, Set<String> words) {
    if (pIndex == pattern.length() && sIndex == s.length()) return true;
    if (pIndex == pattern.length() || sIndex == s.length()) return false;

    char p = pattern.charAt(pIndex);
    if (patternMap.containsKey(p)) {
        String word = patternMap.get(p);
        if (!s.startsWith(word, sIndex)) return false;
        return backtrack(pattern, pIndex + 1, s, sIndex + word.length(), patternMap, words);
    } else {
        for (int length = 1; length <= s.length() - sIndex; length++) {
            String word = s.substring(sIndex, sIndex + length);
            if (words.contains(word)) continue;
            patternMap.put(p, word);
            words.add(word);
            if (backtrack(pattern, pIndex + 1, s, sIndex + length, patternMap, words)) return true;
            patternMap.remove(p);
            words.remove(word);
        }
    }
    return false;
}
```
The algorithm uses a recursive depth-fisrt search approach (backtracking) for solving the string matching problem. For each character in the `pattern`, it'll check if the character exists in the `pattern_map`. If it exists and it maps to the string at the current position in `s`, it'll continue checking the remaining patterns and characters in `s`. If it doesn't exist, the function will try to create the mapping of the single character to the substring in `s`. The function will return true if a mapping is found that matches the pattern, else it'll return false. The used mapping is restored (backtracked) in each iteration.

## A solution in C++

```cpp
bool wordPatternMatch(string pattern, string s) {
    unordered_map<char, string> pattern_map;
    unordered_set<string> words;
    return backtrack(pattern, 0, s, 0, pattern_map, words);
}

bool backtrack(string& pattern, int p_index, string& s, int s_index, unordered_map<char, string>& pattern_map, unordered_set<string>& words) {
    if (p_index == pattern.size() && s_index == s.size()) return true;
    if (p_index == pattern.size() || s_index == s.size()) return false;

    char p = pattern[p_index];
    if (pattern_map.count(p)) {
        string word = pattern_map[p];
        if (s.substr(s_index, word.size()) != word) return false;
        return backtrack(pattern, p_index + 1, s, s_index + word.size(), pattern_map, words);
    } else {
        for (int length = 1; length <= s.size() - s_index; length++) {
            string word = s.substr(s_index, length);
            if (words.count(word)) continue;
            pattern_map[p] = word;
            words.insert(word);
            if (backtrack(pattern, p_index + 1, s, s_index + length, pattern_map, words)) return true;
            pattern_map.erase(p);
            words.erase(word);
        }
    }
    return false;
}
```
The algorithm uses a recursive depth-fisrt search approach (backtracking) for solving the string matching problem. For each character in the `pattern`, it'll check if the character exists in the `pattern_map`. If it exists and it maps to the string at the current position in `s`, it'll continue checking the remaining patterns and characters in `s`. If it doesn't exist, the function will try to create the mapping of the single character to the substring in `s`. The function will return true if a mapping is found that matches the pattern, else it'll return false. The used mapping is restored (backtracked) in each iteration.

## A solution in Python

```python
def wordPatternMatch(pattern: str, s: str) -> bool:
    def backtrack(p_index, s_index, pattern_map, words):
        if p_index == len(pattern) and s_index == len(s):
            return True
        if p_index == len(pattern) or s_index == len(s):
            return False

        p = pattern[p_index]
        if p in pattern_map:
            word = pattern_map[p]
            if not s.startswith(word, s_index):
                return False
            return backtrack(p_index + 1, s_index + len(word), pattern_map, words)
        else:
            for length in range(1, len(s) - s_index + 1):
                word = s[s_index : s_index + length]
                if word in words:
                    continue
                pattern_map[p] = word
                words.add(word)
                if backtrack(p_index + 1, s_index + length, pattern_map, words):
                    return True
                pattern_map.pop(p)
                words.remove(word)
        return False

    return backtrack(0, 0, {}, set())
```
The algorithm uses a recursive depth-fisrt search approach (backtracking) for solving the string matching problem. For each character in the `pattern`, it'll check if the character exists in the `pattern_map`. If it exists and it maps to the string at the current position in `s`, it'll continue checking the remaining patterns and characters in `s`. If it doesn't exist, the function will try to create the mapping of the single character to the substring in `s`. The function will return true if a mapping is found that matches the pattern, else it'll return false. The used mapping is restored (backtracked) in each iteration.

## A solution in Javascript

```javascript
var wordPatternMatch = function(pattern, s) {
    const patternMap = new Map();
    const words = new Set();
    return backtrack(pattern, 0, s, 0, patternMap, words);

    function backtrack(pattern, pIndex, s, sIndex, patternMap, words) {
        if (pIndex == pattern.length && sIndex == s.length) return true;
        if (pIndex == pattern.length || sIndex == s.length) return false;

        let p = pattern[pIndex];
        if (patternMap.has(p)) {
            let word = patternMap.get(p);
            if (s.slice(sIndex, sIndex + word.length) !== word) return false;
            return backtrack(pattern, pIndex + 1, s, sIndex + word.length, patternMap, words);
        } else {
            for (let length = 1; length <= s.length - sIndex; length++) {
                let word = s.substr(sIndex, length);
                if (words.has(word)) continue;
                patternMap.set(p, word);
                words.add(word);
                if (backtrack(pattern, pIndex + 1, s, sIndex + length, patternMap, words)) return true;
                patternMap.delete(p);
                words.delete(word);
            }
        }
        return false;
    }
};
```
The algorithm uses a recursive depth-fisrt search approach (backtracking) for solving the string matching problem. For each character in the `pattern`, it'll check if the character exists in the `pattern_map`. If it exists and it maps to the string at the current position in `s`, it'll continue checking the remaining patterns and characters in `s`. If it doesn't exist, the function will try to create the mapping of the single character to the substring in `s`. The function will return true if a mapping is found that matches the pattern, else it'll return false. The used mapping is restored (backtracked) in each iteration.


# Nim Game

- slug: nim-game
- difficulty: Easy

You are playing the following Nim Game with your friend:

*   Initially, there is a heap of stones on the table.
*   You and your friend will alternate taking turns, and **you go first**.
*   On each turn, the person whose turn it is will remove 1 to 3 stones from the heap.
*   The one who removes the last stone is the winner.

Given `n`, the number of stones in the heap, return `true` _if you can win the game assuming both you and your friend play optimally, otherwise return_ `false`.

**Example 1:**

**Input:** n = 4
**Output:** false
**Explanation:** These are the possible outcomes:
1. You remove 1 stone. Your friend removes 3 stones, including the last stone. Your friend wins.
2. You remove 2 stones. Your friend removes 2 stones, including the last stone. Your friend wins.
3. You remove 3 stones. Your friend removes the last stone. Your friend wins.
In all outcomes, your friend wins.

**Example 2:**

**Input:** n = 1
**Output:** true

**Example 3:**

**Input:** n = 2
**Output:** true

**Constraints:**

*   `1 <= n <= 231 - 1`

## A solution in Java

```java
public boolean canWinNim(int n) {
    return n % 4 != 0;
}
```
In the Nim game, the optimal strategy is to make the other player take the last stone. The game is won by the player who can force the opponent to take the last stone. If the current number of stones is divisible by 4, the next player can always make the other player take the last stone. Therefore, whenever the current number of stones is divisible by 4, the player will lose. If the number of stones is not divisible by 4, the player can make the next player play with a number of stones divisible by 4, thus making the next player lose.

In the code, we simply check if the number of stones `n` is not divisible by 4 (`n % 4 != 0`), and if it is, then the player can win the game.

## A solution in C++

```cpp
bool canWinNim(int n) {
    return n % 4 != 0;
}
```
In the Nim game, the optimal strategy is to make the other player take the last stone. The game is won by the player who can force the opponent to take the last stone. If the current number of stones is divisible by 4, the next player can always make the other player take the last stone. Therefore, whenever the current number of stones is divisible by 4, the player will lose. If the number of stones is not divisible by 4, the player can make the next player play with a number of stones divisible by 4, thus making the next player lose.

In the code, we simply check if the number of stones `n` is not divisible by 4 (`n % 4 != 0`), and if it is, then the player can win the game.

## A solution in Python

```python
def canWinNim(n):
    return n % 4 != 0
```
In the Nim game, the optimal strategy is to make the other player take the last stone. The game is won by the player who can force the opponent to take the last stone. If the current number of stones is divisible by 4, the next player can always make the other player take the last stone. Therefore, whenever the current number of stones is divisible by 4, the player will lose. If the number of stones is not divisible by 4, the player can make the next player play with a number of stones divisible by 4, thus making the next player lose.

In the code, we simply check if the number of stones `n` is not divisible by 4 (`n % 4 != 0`), and if it is, then the player can win the game.

## A solution in Javascript

```javascript
function canWinNim(n) {
    return n % 4 !== 0;
}
```
In the Nim game, the optimal strategy is to make the other player take the last stone. The game is won by the player who can force the opponent to take the last stone. If the current number of stones is divisible by 4, the next player can always make the other player take the last stone. Therefore, whenever the current number of stones is divisible by 4, the player will lose. If the number of stones is not divisible by 4, the player can make the next player play with a number of stones divisible by 4, thus making the next player lose.

In the code, we simply check if the number of stones `n` is not divisible by 4 (`n % 4 != 0`), and if it is, then the player can win the game.


# Flip Game

- slug: flip-game
- difficulty: Easy

You are playing a Flip Game with your friend.

You are given a string `currentState` that contains only `'+'` and `'-'`. You and your friend take turns to flip **two consecutive** `"++ "` into `"-- "`. The game ends when a person can no longer make a move, and therefore the other person will be the winner.

Return all possible states of the string `currentState` after **one valid move**. You may return the answer in **any order**. If there is no valid move, return an empty list `[]`.

**Example 1:**

**Input:** currentState =  "++++ "
**Output:** \[ "--++ ", "+--+ ", "++-- "\]

**Example 2:**

**Input:** currentState =  "+ "
**Output:** \[\]

**Constraints:**

*   `1 <= currentState.length <= 500`
*   `currentState[i]` is either `'+'` or `'-'`.

## A solution in Java

```java
import java.util.ArrayList;
import java.util.List;

public List<String> generatePossibleNextMoves(String currentState) {
    List<String> result = new ArrayList<>();
    for (int i = 1; i < currentState.length(); i++) {
        if (currentState.charAt(i) == '+' && currentState.charAt(i - 1) == '+') {
            result.add(currentState.substring(0, i - 1) + "--" + currentState.substring(i + 1));
        }
    }
    return result;
}
```
The algorithm iterates through the `currentState` string starting from the second character to check for two consecutive `'+'` characters. When it finds a pair, it flips them to `'-'` and adds the resulting string to the `result` list. After adding the result, it flips the characters back to `'+'` to continue searching for more pairs.

In Python and JavaScript, the string concatenation is done using slicing and concatenation, while in C++ and Java, the strings are first modified and then restored to their original state after adding the modified result. The final output is a list of all the possible next moves after one valid flip.

## A solution in C++

```cpp
#include <vector>
#include <string>

std::vector<std::string> generatePossibleNextMoves(std::string currentState) {
    std::vector<std::string> result;
    for (int i = 1; i < currentState.size(); ++i) {
        if (currentState[i] == '+' && currentState[i - 1] == '+') {
            currentState[i] = currentState[i - 1] = '-';
            result.push_back(currentState);
            currentState[i] = currentState[i - 1] = '+';
        }
    }
    return result;
}
```
The algorithm iterates through the `currentState` string starting from the second character to check for two consecutive `'+'` characters. When it finds a pair, it flips them to `'-'` and adds the resulting string to the `result` list. After adding the result, it flips the characters back to `'+'` to continue searching for more pairs.

In Python and JavaScript, the string concatenation is done using slicing and concatenation, while in C++ and Java, the strings are first modified and then restored to their original state after adding the modified result. The final output is a list of all the possible next moves after one valid flip.

## A solution in Python

```python
def generate_possible_next_moves(current_state):
    result = []
    for i in range(1, len(current_state)):
        if current_state[i] == '+' and current_state[i - 1] == '+':
            result.append(current_state[:i - 1] + '--' + current_state[i + 1:])
    return result
```
The algorithm iterates through the `currentState` string starting from the second character to check for two consecutive `'+'` characters. When it finds a pair, it flips them to `'-'` and adds the resulting string to the `result` list. After adding the result, it flips the characters back to `'+'` to continue searching for more pairs.

In Python and JavaScript, the string concatenation is done using slicing and concatenation, while in C++ and Java, the strings are first modified and then restored to their original state after adding the modified result. The final output is a list of all the possible next moves after one valid flip.

## A solution in Javascript

```javascript
function generatePossibleNextMoves(currentState) {
    const result = [];
    for (let i = 1; i < currentState.length; i++) {
        if (currentState[i] === '+' && currentState[i - 1] === '+') {
            result.push(currentState.slice(0, i - 1) + '--' + currentState.slice(i + 1));
        }
    }
    return result;
}
```
The algorithm iterates through the `currentState` string starting from the second character to check for two consecutive `'+'` characters. When it finds a pair, it flips them to `'-'` and adds the resulting string to the `result` list. After adding the result, it flips the characters back to `'+'` to continue searching for more pairs.

In Python and JavaScript, the string concatenation is done using slicing and concatenation, while in C++ and Java, the strings are first modified and then restored to their original state after adding the modified result. The final output is a list of all the possible next moves after one valid flip.


# Flip Game II

- slug: flip-game-ii
- difficulty: Medium

You are playing a Flip Game with your friend.

You are given a string `currentState` that contains only `'+'` and `'-'`. You and your friend take turns to flip **two consecutive** `"++ "` into `"-- "`. The game ends when a person can no longer make a move, and therefore the other person will be the winner.

Return `true` _if the starting player can **guarantee a win**_, and `false` otherwise.

**Example 1:**

**Input:** currentState =  "++++ "
**Output:** true
**Explanation:** The starting player can guarantee a win by flipping the middle  "++ " to become  "+--+ ".

**Example 2:**

**Input:** currentState =  "+ "
**Output:** false

**Constraints:**

*   `1 <= currentState.length <= 60`
*   `currentState[i]` is either `'+'` or `'-'`.

**Follow up:** Derive your algorithm's runtime complexity.

## A solution in Java

```java
public boolean canWin(String currentState) {
    for (int i = 0; i < currentState.length() - 1; ++i) {
        if (currentState.charAt(i) == '+' && currentState.charAt(i + 1) == '+') {
            String temp = currentState.substring(0, i) + "--" + currentState.substring(i + 2);
            if (!canWin(temp)) return true;
        }
    }
    return false;
}
```
The algorithm uses a recursive approach to check for all possible game states starting from the given `currentState`. At each step, the code iterates through the string to find two consecutive '+' characters. If found, it flips the two consecutive '+' to '--' and calls the function recursively with this newState to check if the opponent wins or not. If the opponent doesn't win, the function returns true as it guarantees a win for the starting player. If no such situation occurs, the function returns false.

The runtime complexity of this algorithm is O(n * 2^n) where n is the length of the input string. The reason for this complexity is that, in the worst-case, we may have to explore every possible state of the game tree, and there are 2^n possible game states.

## A solution in C++

```cpp
bool canWin(string currentState) {
    for (int i = 0; i < currentState.size() - 1; ++i) {
        if (currentState[i] == '+' && currentState[i + 1] == '+') {
            currentState[i] = '-';
            currentState[i + 1] = '-';
            bool opponentWins = canWin(currentState);
            currentState[i] = '+';
            currentState[i + 1] = '+';
            if (!opponentWins) return true;
        }
    }
    return false;
}
```
The algorithm uses a recursive approach to check for all possible game states starting from the given `currentState`. At each step, the code iterates through the string to find two consecutive '+' characters. If found, it flips the two consecutive '+' to '--' and calls the function recursively with this newState to check if the opponent wins or not. If the opponent doesn't win, the function returns true as it guarantees a win for the starting player. If no such situation occurs, the function returns false.

The runtime complexity of this algorithm is O(n * 2^n) where n is the length of the input string. The reason for this complexity is that, in the worst-case, we may have to explore every possible state of the game tree, and there are 2^n possible game states.

## A solution in Python

```python
def canWin(currentState: str) -> bool:
    for i in range(len(currentState) - 1):
        if currentState[i] == '+' and currentState[i + 1] == '+':
            temp = currentState[:i] + "--" + currentState[i + 2:]
            if not canWin(temp):
                return True
    return False
```
The algorithm uses a recursive approach to check for all possible game states starting from the given `currentState`. At each step, the code iterates through the string to find two consecutive '+' characters. If found, it flips the two consecutive '+' to '--' and calls the function recursively with this newState to check if the opponent wins or not. If the opponent doesn't win, the function returns true as it guarantees a win for the starting player. If no such situation occurs, the function returns false.

The runtime complexity of this algorithm is O(n * 2^n) where n is the length of the input string. The reason for this complexity is that, in the worst-case, we may have to explore every possible state of the game tree, and there are 2^n possible game states.

## A solution in Javascript

```javascript
function canWin(currentState) {
    for (let i = 0; i < currentState.length - 1; ++i) {
        if (currentState[i] === '+' && currentState[i + 1] === '+') {
            let temp = currentState.slice(0, i) + "--" + currentState.slice(i + 2);
            if (!canWin(temp)) return true;
        }
    }
    return false;
}
```
The algorithm uses a recursive approach to check for all possible game states starting from the given `currentState`. At each step, the code iterates through the string to find two consecutive '+' characters. If found, it flips the two consecutive '+' to '--' and calls the function recursively with this newState to check if the opponent wins or not. If the opponent doesn't win, the function returns true as it guarantees a win for the starting player. If no such situation occurs, the function returns false.

The runtime complexity of this algorithm is O(n * 2^n) where n is the length of the input string. The reason for this complexity is that, in the worst-case, we may have to explore every possible state of the game tree, and there are 2^n possible game states.


# Find Median from Data Stream

- slug: find-median-from-data-stream
- difficulty: Hard

The **median** is the middle value in an ordered integer list. If the size of the list is even, there is no middle value, and the median is the mean of the two middle values.

*   For example, for `arr = [2,3,4]`, the median is `3`.
*   For example, for `arr = [2,3]`, the median is `(2 + 3) / 2 = 2.5`.

Implement the MedianFinder class:

*   `MedianFinder()` initializes the `MedianFinder` object.
*   `void addNum(int num)` adds the integer `num` from the data stream to the data structure.
*   `double findMedian()` returns the median of all elements so far. Answers within `10-5` of the actual answer will be accepted.

**Example 1:**

**Input**
\[ "MedianFinder ",  "addNum ",  "addNum ",  "findMedian ",  "addNum ",  "findMedian "\]
\[\[\], \[1\], \[2\], \[\], \[3\], \[\]\]
**Output**
\[null, null, null, 1.5, null, 2.0\]

**Explanation**
MedianFinder medianFinder = new MedianFinder();
medianFinder.addNum(1);    // arr = \[1\]
medianFinder.addNum(2);    // arr = \[1, 2\]
medianFinder.findMedian(); // return 1.5 (i.e., (1 + 2) / 2)
medianFinder.addNum(3);    // arr\[1, 2, 3\]
medianFinder.findMedian(); // return 2.0

**Constraints:**

*   `-105 <= num <= 105`
*   There will be at least one element in the data structure before calling `findMedian`.
*   At most `5 * 104` calls will be made to `addNum` and `findMedian`.

**Follow up:**

*   If all integer numbers from the stream are in the range `[0, 100]`, how would you optimize your solution?
*   If `99%` of all integer numbers from the stream are in the range `[0, 100]`, how would you optimize your solution?

## A solution in Java

```java
import java.util.*;

class MedianFinder {
    PriorityQueue<Integer> left;
    PriorityQueue<Integer> right;

    public MedianFinder() {
        left = new PriorityQueue<>((a, b) -> b.compareTo(a));
        right = new PriorityQueue<>();
    }

    public void addNum(int num) {
        if (left.isEmpty() || num <= left.peek()) {
            left.offer(num);
        } else {
            right.offer(num);
        }

        if (left.size() < right.size()) {
            left.offer(right.poll());
        } else if (left.size() > right.size() + 1) {
            right.offer(left.poll());
        }
    }

    public double findMedian() {
        if (left.size() == right.size()) {
            return (left.peek() + right.peek()) / 2.0;
        } else {
            return left.peek();
        }
    }
}
```
The algorithm for solving the median in a list of integers works by maintaining two heaps, a max-heap for the left half and a min-heap for the right half. When a new number is added, it is compared to the max value of the left max-heap. If the number is smaller or equal, it is added to the left heap. If the number is larger, it is added to the right min-heap. Then, we balance the two heaps by ensuring that their sizes never differ by more than one. This ensures that the median is always easily accessible as either the largest value in the left heap or the average of the largest value in the left heap and the smallest value in the right heap. The algorithm has an O(log N) time complexity, where N is the number of elements in the list.

## A solution in C++

```cpp
#include <queue>
using namespace std;

class MedianFinder {
public:
    /** initialize your data structure here. */
    priority_queue<int> left;
    priority_queue<int, vector<int>, greater<int> > right;

    MedianFinder() {}

    void addNum(int num) {
        if (left.empty() || num <= left.top()) {
            left.push(num);
        } else {
            right.push(num);
        }

        if (left.size() < right.size()) {
            left.push(right.top());
            right.pop();
        } else if (left.size() > right.size() + 1) {
            right.push(left.top());
            left.pop();
        }
    }

    double findMedian() {
        if(left.size() == right.size()){
            return ((double)left.top() + (double)right.top()) / 2;
        }
        else{
            return left.top();
        }
    }
};
```
The algorithm for solving the median in a list of integers works by maintaining two heaps, a max-heap for the left half and a min-heap for the right half. When a new number is added, it is compared to the max value of the left max-heap. If the number is smaller or equal, it is added to the left heap. If the number is larger, it is added to the right min-heap. Then, we balance the two heaps by ensuring that their sizes never differ by more than one. This ensures that the median is always easily accessible as either the largest value in the left heap or the average of the largest value in the left heap and the smallest value in the right heap. The algorithm has an O(log N) time complexity, where N is the number of elements in the list.

## A solution in Python

```python
import heapq

class MedianFinder:
    def __init__(self):
        self.left = []  # max heap
        self.right = []  # min heap

    def addNum(self, num: int) -> None:
        if not self.left or num <= -self.left[0]:
            heapq.heappush(self.left, -num)
        else:
            heapq.heappush(self.right, num)

        if len(self.left) < len(self.right):
            heapq.heappush(self.left, -heapq.heappop(self.right))
        elif len(self.left) > len(self.right) + 1:
            heapq.heappush(self.right, -heapq.heappop(self.left))

    def findMedian(self) -> float:
        if len(self.left) == len(self.right):
            return (-self.left[0] + self.right[0]) / 2
        else:
            return -self.left[0]
```
The algorithm for solving the median in a list of integers works by maintaining two heaps, a max-heap for the left half and a min-heap for the right half. When a new number is added, it is compared to the max value of the left max-heap. If the number is smaller or equal, it is added to the left heap. If the number is larger, it is added to the right min-heap. Then, we balance the two heaps by ensuring that their sizes never differ by more than one. This ensures that the median is always easily accessible as either the largest value in the left heap or the average of the largest value in the left heap and the smallest value in the right heap. The algorithm has an O(log N) time complexity, where N is the number of elements in the list.

## A solution in Javascript

```javascript
class MedianFinder {
    constructor() {
        this.left = new MaxPriorityQueue();
        this.right = new MinPriorityQueue();
    }

    addNum(num) {
        if (this.left.isEmpty() || num <= this.left.peek().element) {
            this.left.enqueue(num);
        } else {
            this.right.enqueue(num);
        }

        if (this.left.size() < this.right.size()) {
            this.left.enqueue(this.right.dequeue().element);
        } else if (this.left.size() > this.right.size() + 1) {
            this.right.enqueue(this.left.dequeue().element);
        }
    }

    findMedian() {
        if (this.left.size() === this.right.size()) {
            return (this.left.peek().element + this.right.peek().element) / 2.0;
        } else {
            return this.left.peek().element;
        }
    }
}
```
The algorithm for solving the median in a list of integers works by maintaining two heaps, a max-heap for the left half and a min-heap for the right half. When a new number is added, it is compared to the max value of the left max-heap. If the number is smaller or equal, it is added to the left heap. If the number is larger, it is added to the right min-heap. Then, we balance the two heaps by ensuring that their sizes never differ by more than one. This ensures that the median is always easily accessible as either the largest value in the left heap or the average of the largest value in the left heap and the smallest value in the right heap. The algorithm has an O(log N) time complexity, where N is the number of elements in the list.


# Best Meeting Point

- slug: best-meeting-point
- difficulty: Hard

Given an `m x n` binary grid `grid` where each `1` marks the home of one friend, return _the minimal **total travel distance**_.

The **total travel distance** is the sum of the distances between the houses of the friends and the meeting point.

The distance is calculated using [Manhattan Distance](http://en.wikipedia.org/wiki/Taxicab_geometry), where `distance(p1, p2) = |p2.x - p1.x| + |p2.y - p1.y|`.

**Example 1:**

**Input:** grid = \[\[1,0,0,0,1\],\[0,0,0,0,0\],\[0,0,1,0,0\]\]
**Output:** 6
**Explanation:** Given three friends living at (0,0), (0,4), and (2,2).
The point (0,2) is an ideal meeting point, as the total travel distance of 2 + 2 + 2 = 6 is minimal.
So return 6.

**Example 2:**

**Input:** grid = \[\[1,1\]\]
**Output:** 1

**Constraints:**

*   `m == grid.length`
*   `n == grid[i].length`
*   `1 <= m, n <= 200`
*   `grid[i][j]` is either `0` or `1`.
*   There will be **at least two** friends in the `grid`.

## A solution in Java

```java
public int minTotalDistance(int[][] grid) {
    List<Integer> rows = new ArrayList<Integer>();
    List<Integer> cols = new ArrayList<Integer>();
    int m = grid.length, n = grid[0].length;
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            if (grid[i][j] == 1) {
                rows.add(i);
                cols.add(j);
            }
        }
    }
    Collections.sort(cols);
    int row_median = rows.get(rows.size() / 2), col_median = cols.get(cols.size() / 2);
    int distance = 0;
    for (int i : rows) distance += Math.abs(i - row_median);
    for (int j : cols) distance += Math.abs(j - col_median);
    return distance;
}
```
1. Iterate through the given grid and store the row and column indices separately for each friend's home.
2. Sort the columns list.
3. Find the median of row and column separately (using middle element in sorted list) as it represents the optimal meeting point.
4. Calculate the total distance by summing up Manhattan Distance for each friend to the meeting point.

## A solution in C++

```cpp
int minTotalDistance(vector<vector<int>>& grid) {
    vector<int> rows, cols;
    int m = grid.size(), n = grid[0].size();
    for (int i = 0; i < m; ++i) {
        for (int j = 0; j < n; ++j) {
            if (grid[i][j]) {
                rows.push_back(i);
                cols.push_back(j);
            }
        }
    }
    sort(cols.begin(), cols.end());
    int row_median = rows[rows.size() / 2], col_median = cols[cols.size() / 2];
    int distance = 0;
    for (int i : rows) distance += abs(i - row_median);
    for (int j : cols) distance += abs(j - col_median);
    return distance;
}
```
1. Iterate through the given grid and store the row and column indices separately for each friend's home.
2. Sort the columns list.
3. Find the median of row and column separately (using middle element in sorted list) as it represents the optimal meeting point.
4. Calculate the total distance by summing up Manhattan Distance for each friend to the meeting point.

## A solution in Python

```python
def minTotalDistance(grid):
    m, n = len(grid), len(grid[0])
    rows, cols = [], []
    for i in range(m):
        for j in range(n):
            if grid[i][j] == 1:
                rows.append(i)
                cols.append(j)

    cols.sort()
    row_median, col_median = rows[len(rows) // 2], cols[len(cols) // 2]
    distance = sum(abs(i - row_median) for i in rows) + sum(abs(j - col_median) for j in cols)
    return distance
```
1. Iterate through the given grid and store the row and column indices separately for each friend's home.
2. Sort the columns list.
3. Find the median of row and column separately (using middle element in sorted list) as it represents the optimal meeting point.
4. Calculate the total distance by summing up Manhattan Distance for each friend to the meeting point.

## A solution in Javascript

```javascript
var minTotalDistance = function(grid) {
    let m = grid.length, n = grid[0].length;
    let rows = [], cols = [];
    for (let i = 0; i < m; ++i) {
        for (let j = 0; j < n; ++j) {
            if (grid[i][j] === 1) {
                rows.push(i);
                cols.push(j);
            }
        }
    }
    cols.sort((a, b) => a - b);
    let row_median = rows[Math.floor(rows.length / 2)], col_median = cols[Math.floor(cols.length / 2)];
    let distance = rows.reduce((acc, i) => acc + Math.abs(i - row_median), 0) + cols.reduce((acc, j) => acc + Math.abs(j - col_median), 0);
    return distance;
};
```
1. Iterate through the given grid and store the row and column indices separately for each friend's home.
2. Sort the columns list.
3. Find the median of row and column separately (using middle element in sorted list) as it represents the optimal meeting point.
4. Calculate the total distance by summing up Manhattan Distance for each friend to the meeting point.


# Serialize and Deserialize Binary Tree

- slug: serialize-and-deserialize-binary-tree
- difficulty: Hard

Serialization is the process of converting a data structure or object into a sequence of bits so that it can be stored in a file or memory buffer, or transmitted across a network connection link to be reconstructed later in the same or another computer environment.

Design an algorithm to serialize and deserialize a binary tree. There is no restriction on how your serialization/deserialization algorithm should work. You just need to ensure that a binary tree can be serialized to a string and this string can be deserialized to the original tree structure.

**Clarification:** The input/output format is the same as [how LeetCode serializes a binary tree](https://support.leetcode.com/hc/en-us/articles/360011883654-What-does-1-null-2-3-mean-in-binary-tree-representation-). You do not necessarily need to follow this format, so please be creative and come up with different approaches yourself.

**Example 1:**

**Input:** root = \[1,2,3,null,null,4,5\]
**Output:** \[1,2,3,null,null,4,5\]

**Example 2:**

**Input:** root = \[\]
**Output:** \[\]

**Constraints:**

*   The number of nodes in the tree is in the range `[0, 104]`.
*   `-1000 <= Node.val <= 1000`

## A solution in Java

```java
import java.util.LinkedList;
import java.util.Queue;
import java.util.Arrays;

public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public String serialize(TreeNode root) {
    if (root == null) return "null,";
    return root.val + "," + serialize(root.left) + serialize(root.right);
}

public TreeNode deserialize(String data) {
    Queue<String> queue = new LinkedList<>(Arrays.asList(data.split(",")));
    return deserializeHelper(queue);
}

private TreeNode deserializeHelper(Queue<String> queue) {
    String val = queue.poll();
    if (val.equals("null")) return null;
    TreeNode root = new TreeNode(Integer.parseInt(val));
    root.left = deserializeHelper(queue);
    root.right = deserializeHelper(queue);
    return root;
}
```
The algorithm uses a Depth-First Search traversal (specifically, pre-order) to serialize the binary tree into a comma-separated string. Each empty node is represented by a "null" string.

To deserialize the data string back into a tree structure, the algorithm processes the comma-separated string and interprets each item it encounters. If the item is "null", it sets the node to null. Otherwise, it creates a TreeNode with the value and recursively sets left and right children. The deserialization also uses a pre-order traversal, which corresponds to the serialized string format. This approach ensures that the deserialized tree retains the same structure as the original tree.

## A solution in C++

```cpp
#include <sstream>
#include <string>
#include <queue>

using namespace std;

struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
};

string serialize(TreeNode* root) {
    if (!root) return "null,";
    return to_string(root->val) + "," + serialize(root->left) + serialize(root->right);
}

TreeNode* deserialize(string data) {
    istringstream is(data);
    return deserializeHelper(is);
}

TreeNode* deserializeHelper(istringstream& is) {
    string val;
    if (!getline(is, val, ',')) return nullptr;
    if (val == "null") return nullptr;
    TreeNode* root = new TreeNode(stoi(val));
    root->left = deserializeHelper(is);
    root->right = deserializeHelper(is);
    return root;
}
```
The algorithm uses a Depth-First Search traversal (specifically, pre-order) to serialize the binary tree into a comma-separated string. Each empty node is represented by a "null" string.

To deserialize the data string back into a tree structure, the algorithm processes the comma-separated string and interprets each item it encounters. If the item is "null", it sets the node to null. Otherwise, it creates a TreeNode with the value and recursively sets left and right children. The deserialization also uses a pre-order traversal, which corresponds to the serialized string format. This approach ensures that the deserialized tree retains the same structure as the original tree.

## A solution in Python

```python
class TreeNode:
    def __init__(self, x):
        self.val = x
        self.left = None
        self.right = None

def serialize(root):
    if not root: return "null,"
    return str(root.val) + "," + serialize(root.left) + serialize(root.right)

def deserialize(data):
    def deserialize_helper(values):
        val = values.pop(0)
        if val == 'null': return None
        root = TreeNode(int(val))
        root.left = deserialize_helper(values)
        root.right = deserialize_helper(values)
        return root

    values = data.split(",")
    return deserialize_helper(values[:-1])  # Excluding the last empty element
```
The algorithm uses a Depth-First Search traversal (specifically, pre-order) to serialize the binary tree into a comma-separated string. Each empty node is represented by a "null" string.

To deserialize the data string back into a tree structure, the algorithm processes the comma-separated string and interprets each item it encounters. If the item is "null", it sets the node to null. Otherwise, it creates a TreeNode with the value and recursively sets left and right children. The deserialization also uses a pre-order traversal, which corresponds to the serialized string format. This approach ensures that the deserialized tree retains the same structure as the original tree.

## A solution in Javascript

```javascript
class TreeNode {
    constructor(val, left = null, right = null) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

function serialize(root) {
    if (!root) return "null,";
    return root.val + "," + serialize(root.left) + serialize(root.right);
}

function deserialize(data) {
    const values = data.split(",");

    function deserializeHelper() {
        const val = values.shift();
        if (val === "null") return null;
        const root = new TreeNode(parseInt(val));
        root.left = deserializeHelper();
        root.right = deserializeHelper();
        return root;
    }

    return deserializeHelper();
}
```
The algorithm uses a Depth-First Search traversal (specifically, pre-order) to serialize the binary tree into a comma-separated string. Each empty node is represented by a "null" string.

To deserialize the data string back into a tree structure, the algorithm processes the comma-separated string and interprets each item it encounters. If the item is "null", it sets the node to null. Otherwise, it creates a TreeNode with the value and recursively sets left and right children. The deserialization also uses a pre-order traversal, which corresponds to the serialized string format. This approach ensures that the deserialized tree retains the same structure as the original tree.


# Binary Tree Longest Consecutive Sequence

- slug: binary-tree-longest-consecutive-sequence
- difficulty: Medium

Given the `root` of a binary tree, return _the length of the longest **consecutive sequence path**_.

A **consecutive sequence path** is a path where the values **increase by one** along the path.

Note that the path can start **at any node** in the tree, and you cannot go from a node to its parent in the path.

**Example 1:**

**Input:** root = \[1,null,3,2,4,null,null,null,5\]
**Output:** 3
**Explanation:** Longest consecutive sequence path is 3-4-5, so return 3.

**Example 2:**

**Input:** root = \[2,null,3,2,null,1\]
**Output:** 2
**Explanation:** Longest consecutive sequence path is 2-3, not 3-2-1, so return 2.

**Constraints:**

*   The number of nodes in the tree is in the range `[1, 3 * 104]`.
*   `-3 * 104 <= Node.val <= 3 * 104`

## A solution in Java

```java
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode(int x) { val = x; }
}

public int longestConsecutiveSequence(TreeNode root, int[] longestPath) {
    if (root == null) {
        return 0;
    }
    int left = longestConsecutiveSequence(root.left, longestPath);
    int right = longestConsecutiveSequence(root.right, longestPath);
    int currPath = 1;
    if (root.left != null && root.left.val == root.val + 1) {
        currPath = Math.max(currPath, left + 1);
    }
    if (root.right != null && root.right.val == root.val + 1) {
        currPath = Math.max(currPath, right + 1);
    }
    longestPath[0] = Math.max(longestPath[0], currPath);
    return currPath;
}

public int longestConsecutive(TreeNode root) {
    int[] longestPath = new int[1];
    longestConsecutiveSequence(root, longestPath);
    return longestPath[0];
}
```
The solution is using depth-first search on the binary tree with a recursive function `longestConsecutiveSequence`. This function takes a node as input and returns the longest path of consecutive values that starts at that node. It also updates an array `longestPath` that stores the longest path seen so far, allowing multiple levels of the recursive function calls to access and update it.

For each node, the function first calls itself recursively for left and right child nodes. Then, it checks if the left and right children are consecutive values to the current value, and if so, adds the corresponding paths to `currPath`. Finally, it compares `currPath` with the maximum path found so far and updates the `longestPath` array accordingly. The longest consecutive path is returned after the recursion is complete.

## A solution in C++

```cpp
struct TreeNode {
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode(int x) : val(x), left(NULL), right(NULL) {}
};

int longestConsecutiveSequence(TreeNode* root, int &longestPath) {
    if (root == NULL) {
        return 0;
    }
    int left = longestConsecutiveSequence(root->left, longestPath);
    int right = longestConsecutiveSequence(root->right, longestPath);
    int currPath = 1;
    if (root->left != NULL && root->left->val == root->val + 1) {
        currPath = max(currPath, left + 1);
    }
    if (root->right != NULL && root->right->val == root->val + 1) {
        currPath = max(currPath, right + 1);
    }
    longestPath = max(longestPath, currPath);
    return currPath;
}

int longestConsecutive(TreeNode* root) {
    int longestPath = 0;
    longestConsecutiveSequence(root, longestPath);
    return longestPath;
}
```
The solution is using depth-first search on the binary tree with a recursive function `longestConsecutiveSequence`. This function takes a node as input and returns the longest path of consecutive values that starts at that node. It also updates an array `longestPath` that stores the longest path seen so far, allowing multiple levels of the recursive function calls to access and update it.

For each node, the function first calls itself recursively for left and right child nodes. Then, it checks if the left and right children are consecutive values to the current value, and if so, adds the corresponding paths to `currPath`. Finally, it compares `currPath` with the maximum path found so far and updates the `longestPath` array accordingly. The longest consecutive path is returned after the recursion is complete.

## A solution in Python

```python
class TreeNode:
    def __init__(self, val=0, left=None, right=None):
        self.val = val
        self.left = left
        self.right = right

def longest_consecutive_sequence(root, longest_path):
    if root is None:
        return 0
    left = longest_consecutive_sequence(root.left, longest_path)
    right = longest_consecutive_sequence(root.right, longest_path)
    curr_path = 1
    if root.left and root.left.val == root.val + 1:
        curr_path = max(curr_path, left + 1)
    if root.right and root.right.val == root.val + 1:
        curr_path = max(curr_path, right + 1)
    longest_path[0] = max(longest_path[0], curr_path)
    return curr_path

def longest_consecutive(root):
    longest_path = [0]
    longest_consecutive_sequence(root, longest_path)
    return longest_path[0]
```
The solution is using depth-first search on the binary tree with a recursive function `longestConsecutiveSequence`. This function takes a node as input and returns the longest path of consecutive values that starts at that node. It also updates an array `longestPath` that stores the longest path seen so far, allowing multiple levels of the recursive function calls to access and update it.

For each node, the function first calls itself recursively for left and right child nodes. Then, it checks if the left and right children are consecutive values to the current value, and if so, adds the corresponding paths to `currPath`. Finally, it compares `currPath` with the maximum path found so far and updates the `longestPath` array accordingly. The longest consecutive path is returned after the recursion is complete.

## A solution in Javascript

```javascript
class TreeNode {
    constructor(val, left = null, right = null) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

function longestConsecutiveSequence(root, longestPath) {
    if (!root) {
        return 0;
    }
    const left = longestConsecutiveSequence(root.left, longestPath);
    const right = longestConsecutiveSequence(root.right, longestPath);
    let currPath = 1;
    if (root.left && root.left.val === root.val + 1) {
        currPath = Math.max(currPath, left + 1);
    }
    if (root.right && root.right.val === root.val + 1) {
        currPath = Math.max(currPath, right + 1);
    }
    longestPath[0] = Math.max(longestPath[0], currPath);
    return currPath;
}

function longestConsecutive(root) {
    const longestPath = [0];
    longestConsecutiveSequence(root, longestPath);
    return longestPath[0];
}
```
The solution is using depth-first search on the binary tree with a recursive function `longestConsecutiveSequence`. This function takes a node as input and returns the longest path of consecutive values that starts at that node. It also updates an array `longestPath` that stores the longest path seen so far, allowing multiple levels of the recursive function calls to access and update it.

For each node, the function first calls itself recursively for left and right child nodes. Then, it checks if the left and right children are consecutive values to the current value, and if so, adds the corresponding paths to `currPath`. Finally, it compares `currPath` with the maximum path found so far and updates the `longestPath` array accordingly. The longest consecutive path is returned after the recursion is complete.


# Bulls and Cows

- slug: bulls-and-cows
- difficulty: Medium

You are playing the **[Bulls and Cows](https://en.wikipedia.org/wiki/Bulls_and_Cows)** game with your friend.

You write down a secret number and ask your friend to guess what the number is. When your friend makes a guess, you provide a hint with the following info:

*   The number of "bulls ", which are digits in the guess that are in the correct position.
*   The number of "cows ", which are digits in the guess that are in your secret number but are located in the wrong position. Specifically, the non-bull digits in the guess that could be rearranged such that they become bulls.

Given the secret number `secret` and your friend's guess `guess`, return _the hint for your friend's guess_.

The hint should be formatted as `"xAyB "`, where `x` is the number of bulls and `y` is the number of cows. Note that both `secret` and `guess` may contain duplicate digits.

**Example 1:**

**Input:** secret =  "1807 ", guess =  "7810 "
**Output:**  "1A3B "
**Explanation:** Bulls are connected with a '|' and cows are underlined:
 "1807 "
  |
 "7810 "

**Example 2:**

**Input:** secret =  "1123 ", guess =  "0111 "
**Output:**  "1A1B "
**Explanation:** Bulls are connected with a '|' and cows are underlined:
 "1123 "         "1123 "
  |      or     |
 "0111 "         "0111 "
Note that only one of the two unmatched 1s is counted as a cow since the non-bull digits can only be rearranged to allow one 1 to be a bull.

**Constraints:**

*   `1 <= secret.length, guess.length <= 1000`
*   `secret.length == guess.length`
*   `secret` and `guess` consist of digits only.

## A solution in Java

```java
public String getHint(String secret, String guess) {
    int bulls = 0, cows = 0;
    int[] secretCount = new int[10];
    int[] guessCount = new int[10];

    for (int i = 0; i < secret.length(); i++) {
        if (secret.charAt(i) == guess.charAt(i)) {
            bulls++;
        } else {
            secretCount[secret.charAt(i) - '0']++;
            guessCount[guess.charAt(i) - '0']++;
        }
    }

    for (int i = 0; i < 10; i++) {
        cows += Math.min(secretCount[i], guessCount[i]);
    }

    return bulls + "A" + cows + "B";
}
```
The algorithm first initializes the counts for bulls and cows to be 0. We also create two arrays called secret_count and guess_count to store the count of each digit from '0' to '9' in the secret and guess strings.

We then loop through both the secret and the guess strings. For each position, if the digits are the same in both strings (i.e., secret[i] == guess[i]), we increase the bulls count. If not, we increment the corresponding count for the secret and guess digits.

After iterating through the strings, we loop through the count arrays and add the minimum of the counts of each digit in secret_count and guess_count to the cows count.

Finally, we return the result in the "xAyB" format by concatenating the values of bulls and cows.

## A solution in C++

```cpp
std::string getHint(std::string secret, std::string guess) {
    int bulls = 0, cows = 0;
    std::vector<int> secret_count(10, 0);
    std::vector<int> guess_count(10, 0);

    for (size_t i = 0; i < secret.length(); i++) {
        if (secret[i] == guess[i]) {
            bulls++;
        } else {
            secret_count[secret[i] - '0']++;
            guess_count[guess[i] - '0']++;
        }
    }

    for (size_t i = 0; i < 10; i++) {
        cows += std::min(secret_count[i], guess_count[i]);
    }

    return std::to_string(bulls) + "A" + std::to_string(cows) + "B";
}
```
The algorithm first initializes the counts for bulls and cows to be 0. We also create two arrays called secret_count and guess_count to store the count of each digit from '0' to '9' in the secret and guess strings.

We then loop through both the secret and the guess strings. For each position, if the digits are the same in both strings (i.e., secret[i] == guess[i]), we increase the bulls count. If not, we increment the corresponding count for the secret and guess digits.

After iterating through the strings, we loop through the count arrays and add the minimum of the counts of each digit in secret_count and guess_count to the cows count.

Finally, we return the result in the "xAyB" format by concatenating the values of bulls and cows.

## A solution in Python

```python
def get_hint(secret: str, guess: str) -> str:
    bulls = cows = 0
    secret_count = [0] * 10
    guess_count = [0] * 10

    for i in range(len(secret)):
        if secret[i] == guess[i]:
            bulls += 1
        else:
            secret_count[int(secret[i])] += 1
            guess_count[int(guess[i])] += 1

    for i in range(10):
        cows += min(secret_count[i], guess_count[i])

    return f"{bulls}A{cows}B"
```
The algorithm first initializes the counts for bulls and cows to be 0. We also create two arrays called secret_count and guess_count to store the count of each digit from '0' to '9' in the secret and guess strings.

We then loop through both the secret and the guess strings. For each position, if the digits are the same in both strings (i.e., secret[i] == guess[i]), we increase the bulls count. If not, we increment the corresponding count for the secret and guess digits.

After iterating through the strings, we loop through the count arrays and add the minimum of the counts of each digit in secret_count and guess_count to the cows count.

Finally, we return the result in the "xAyB" format by concatenating the values of bulls and cows.

## A solution in Javascript

```javascript
function getHint(secret, guess) {
    let bulls = 0, cows = 0;
    let secretCount = Array(10).fill(0);
    let guessCount = Array(10).fill(0);

    for (let i = 0; i < secret.length; i++) {
        if (secret[i] === guess[i]) {
            bulls++;
        } else {
            secretCount[parseInt(secret[i])]++;
            guessCount[parseInt(guess[i])]++;
        }
    }

    for (let i = 0; i < 10; i++) {
        cows += Math.min(secretCount[i], guessCount[i]);
    }

    return `${bulls}A${cows}B`;
}
```
The algorithm first initializes the counts for bulls and cows to be 0. We also create two arrays called secret_count and guess_count to store the count of each digit from '0' to '9' in the secret and guess strings.

We then loop through both the secret and the guess strings. For each position, if the digits are the same in both strings (i.e., secret[i] == guess[i]), we increase the bulls count. If not, we increment the corresponding count for the secret and guess digits.

After iterating through the strings, we loop through the count arrays and add the minimum of the counts of each digit in secret_count and guess_count to the cows count.

Finally, we return the result in the "xAyB" format by concatenating the values of bulls and cows.