# Number of Closed Islands

- slug: number-of-closed-islands
- difficulty: Medium

Given a 2D `grid` consists of `0s` (land) and `1s` (water). An _island_ is a maximal 4-directionally connected group of `0s` and a _closed island_ is an island **totally** (all left, top, right, bottom) surrounded by `1s.`

Return the number of _closed islands_.

**Example 1:**

**Input:** grid = \[\[1,1,1,1,1,1,1,0\],\[1,0,0,0,0,1,1,0\],\[1,0,1,0,1,1,1,0\],\[1,0,0,0,0,1,0,1\],\[1,1,1,1,1,1,1,0\]\]
**Output:** 2
**Explanation:**
Islands in gray are closed because they are completely surrounded by water (group of 1s).

**Example 2:**

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

**Example 3:**

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

**Constraints:**

*   `1 <= grid.length, grid[0].length <= 100`
*   `0 <= grid[i][j] <=1`

## A solution in Java

```java
public int closedIsland(int[][] grid) {
    int count = 0;
    for (int i = 0; i < grid.length; i++) {
        for (int j = 0; j < grid[0].length; j++) {
            if (grid[i][j] == 0 && dfs(grid, i, j)) {
                count++;
            }
        }
    }
    return count;
}

private boolean dfs(int[][] grid, int i, int j) {
    if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length) {
        return false;
    }

    if (grid[i][j] == 1) {
        return true;
    }

    grid[i][j] = 1;

    boolean up = dfs(grid, i - 1, j);
    boolean down = dfs(grid, i + 1, j);
    boolean left = dfs(grid, i, j - 1);
    boolean right = dfs(grid, i, j + 1);

    return up && down && left && right;
}
```
The algorithm uses Depth-first Search (DFS) to traverse islands of 0s (land). If the DFS function returns false, then the current cell is on the edge and it is not a closed island. If the DFS function returns true, then the current cell is surrounded by 1s (water), and the current island is a closed island.

For each cell that contains a 0 (land), we call the DFS function to explore the island. If the DFS function returns true for all directions (up, down, left, and right), then it is a closed island. We increment the count for each closed island found.

Finally, we return the total count of closed islands.

## A solution in C++

```cpp
#include <vector>

bool dfs(std::vector<std::vector<int>>& grid, int i, int j) {
    if (i < 0 || j < 0 || i >= grid.size() || j >= grid[0].size()) {
        return false;
    }

    if (grid[i][j] == 1) {
        return true;
    }

    grid[i][j] = 1;

    bool up = dfs(grid, i - 1, j);
    bool down = dfs(grid, i + 1, j);
    bool left = dfs(grid, i, j - 1);
    bool right = dfs(grid, i, j + 1);

    return up && down && left && right;
}

int closedIsland(std::vector<std::vector<int>>& grid) {
    int count = 0;

    for (int i = 0; i < grid.size(); ++i) {
        for (int j = 0; j < grid[0].size(); ++j) {
            if (grid[i][j] == 0 && dfs(grid, i, j)) {
                count++;
            }
        }
    }

    return count;
}
```
The algorithm uses Depth-first Search (DFS) to traverse islands of 0s (land). If the DFS function returns false, then the current cell is on the edge and it is not a closed island. If the DFS function returns true, then the current cell is surrounded by 1s (water), and the current island is a closed island.

For each cell that contains a 0 (land), we call the DFS function to explore the island. If the DFS function returns true for all directions (up, down, left, and right), then it is a closed island. We increment the count for each closed island found.

Finally, we return the total count of closed islands.

## A solution in Python

```python
def closedIsland(grid):
    def dfs(grid, i, j):
        if i < 0 or j < 0 or i >= len(grid) or j >= len(grid[0]):
            return False

        if grid[i][j] == 1:
            return True

        grid[i][j] = 1

        up = dfs(grid, i - 1, j)
        down = dfs(grid, i + 1, j)
        left = dfs(grid, i, j - 1)
        right = dfs(grid, i, j + 1)

        return up and down and left and right

    count = 0
    for i in range(len(grid)):
        for j in range(len(grid[0])):
            if grid[i][j] == 0 and dfs(grid, i, j):
                count += 1

    return count
```
The algorithm uses Depth-first Search (DFS) to traverse islands of 0s (land). If the DFS function returns false, then the current cell is on the edge and it is not a closed island. If the DFS function returns true, then the current cell is surrounded by 1s (water), and the current island is a closed island.

For each cell that contains a 0 (land), we call the DFS function to explore the island. If the DFS function returns true for all directions (up, down, left, and right), then it is a closed island. We increment the count for each closed island found.

Finally, we return the total count of closed islands.

## A solution in Javascript

```javascript
function closedIsland(grid) {
    function dfs(grid, i, j) {
        if (i < 0 || j < 0 || i >= grid.length || j >= grid[0].length) {
            return false;
        }

        if (grid[i][j] == 1) {
            return true;
        }

        grid[i][j] = 1;

        const up = dfs(grid, i - 1, j);
        const down = dfs(grid, i + 1, j);
        const left = dfs(grid, i, j - 1);
        const right = dfs(grid, i, j + 1);

        return up && down && left && right;
    }

    let count = 0;
    for (let i = 0; i < grid.length; i++) {
        for (let j = 0; j < grid[0].length; j++) {
            if (grid[i][j] == 0 && dfs(grid, i, j)) {
                count++;
            }
        }
    }

    return count;
}
```
The algorithm uses Depth-first Search (DFS) to traverse islands of 0s (land). If the DFS function returns false, then the current cell is on the edge and it is not a closed island. If the DFS function returns true, then the current cell is surrounded by 1s (water), and the current island is a closed island.

For each cell that contains a 0 (land), we call the DFS function to explore the island. If the DFS function returns true for all directions (up, down, left, and right), then it is a closed island. We increment the count for each closed island found.

Finally, we return the total count of closed islands.


# Maximum Score Words Formed by Letters

- slug: maximum-score-words-formed-by-letters
- difficulty: Hard

Given a list of `words`, list of single `letters` (might be repeating) and `score` of every character.

Return the maximum score of **any** valid set of words formed by using the given letters (`words[i]` cannot be used two or more times).

It is not necessary to use all characters in `letters` and each letter can only be used once. Score of letters `'a'`, `'b'`, `'c'`, ... ,`'z'` is given by `score[0]`, `score[1]`, ... , `score[25]` respectively.

**Example 1:**

**Input:** words = \[ "dog ", "cat ", "dad ", "good "\], letters = \[ "a ", "a ", "c ", "d ", "d ", "d ", "g ", "o ", "o "\], score = \[1,0,9,5,0,0,3,0,0,0,0,0,0,0,2,0,0,0,0,0,0,0,0,0,0,0\]
**Output:** 23
**Explanation:**
Score  a=1, c=9, d=5, g=3, o=2
Given letters, we can form the words  "dad " (5+1+5) and  "good " (3+2+2+5) with a score of 23.
Words  "dad " and  "dog " only get a score of 21.

**Example 2:**

**Input:** words = \[ "xxxz ", "ax ", "bx ", "cx "\], letters = \[ "z ", "a ", "b ", "c ", "x ", "x ", "x "\], score = \[4,4,4,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,5,0,10\]
**Output:** 27
**Explanation:**
Score  a=4, b=4, c=4, x=5, z=10
Given letters, we can form the words  "ax " (4+5),  "bx " (4+5) and  "cx " (4+5) with a score of 27.
Word  "xxxz " only get a score of 25.

**Example 3:**

**Input:** words = \[ "leetcode "\], letters = \[ "l ", "e ", "t ", "c ", "o ", "d "\], score = \[0,0,1,1,1,0,0,0,0,0,0,1,0,0,1,0,0,0,0,1,0,0,0,0,0,0\]
**Output:** 0
**Explanation:**
Letter  "e " can only be used once.

**Constraints:**

*   `1 <= words.length <= 14`
*   `1 <= words[i].length <= 15`
*   `1 <= letters.length <= 100`
*   `letters[i].length == 1`
*   `score.length == 26`
*   `0 <= score[i] <= 10`
*   `words[i]`, `letters[i]` contains only lower case English letters.

## A solution in Java

```java
public int maxValueAfterReverse(int[] nums) {
    int total = 0, diff = 0;
    int min2 = Integer.MAX_VALUE, max2 = Integer.MIN_VALUE;
    for (int i = 0; i < nums.length - 1; ++i) {
        total += Math.abs(nums[i] - nums[i + 1]);
        min2 = Math.min(min2, Math.max(nums[i], nums[i + 1]));
        max2 = Math.max(max2, Math.min(nums[i], nums[i + 1]));
        diff = Math.max(diff, Math.abs(nums[i + 1] - nums[0]) - Math.abs(nums[i + 1] - nums[i]));
        diff = Math.max(diff, Math.abs(nums[i] - nums[nums.length - 1]) - Math.abs(nums[i] - nums[i + 1]));
    }
    return total + Math.max(diff, 2 * (max2 - min2));
}
```
1. Initialize the required variables for total sum, difference, and minimum and maximum values for further calculations.
2. Iterate through the given array from index 0 to nums.length - 2.
3. Calculate the total sum by adding the absolute difference between nums[i] and nums[i+1].
4. Update the min2 and max2 with the required calculations.
5. Find the maximum possible difference by considering swapping a subarray (0...i+1) or (i...nums.length-1).
6. Return the sum of the total and the maximum value of the calculated difference and 2 times (max2 - min2).

## A solution in C++

```cpp
int maxValueAfterReverse(vector<int>& nums) {
    int total = 0, diff = 0;
    int min2 = INT_MAX, max2 = INT_MIN;
    for (int i = 0; i < nums.size() - 1; ++i) {
        total += abs(nums[i] - nums[i + 1]);
        min2 = min(min2, max(nums[i], nums[i + 1]));
        max2 = max(max2, min(nums[i], nums[i + 1]));
        diff = max(diff, abs(nums[i + 1] - nums[0]) - abs(nums[i + 1] - nums[i]));
        diff = max(diff, abs(nums[i] - nums[nums.size() - 1]) - abs(nums[i] - nums[i + 1]));
    }
    return total + max(diff, 2 * (max2 - min2));
}
```
1. Initialize the required variables for total sum, difference, and minimum and maximum values for further calculations.
2. Iterate through the given array from index 0 to nums.length - 2.
3. Calculate the total sum by adding the absolute difference between nums[i] and nums[i+1].
4. Update the min2 and max2 with the required calculations.
5. Find the maximum possible difference by considering swapping a subarray (0...i+1) or (i...nums.length-1).
6. Return the sum of the total and the maximum value of the calculated difference and 2 times (max2 - min2).

## A solution in Python

```python
def maxValueAfterReverse(nums):
    total, diff = 0, 0
    min2, max2 = float('inf'), float('-inf')
    for i in range(len(nums) - 1):
        total += abs(nums[i] - nums[i + 1])
        min2 = min(min2, max(nums[i], nums[i + 1]))
        max2 = max(max2, min(nums[i], nums[i + 1]))
        diff = max(diff, abs(nums[i + 1] - nums[0]) - abs(nums[i + 1] - nums[i]))
        diff = max(diff, abs(nums[i] - nums[-1]) - abs(nums[i] - nums[i + 1]))
    return total + max(diff, 2 * (max2 - min2))
```
1. Initialize the required variables for total sum, difference, and minimum and maximum values for further calculations.
2. Iterate through the given array from index 0 to nums.length - 2.
3. Calculate the total sum by adding the absolute difference between nums[i] and nums[i+1].
4. Update the min2 and max2 with the required calculations.
5. Find the maximum possible difference by considering swapping a subarray (0...i+1) or (i...nums.length-1).
6. Return the sum of the total and the maximum value of the calculated difference and 2 times (max2 - min2).

## A solution in Javascript

```javascript
function maxValueAfterReverse(nums) {
    let total = 0, diff = 0;
    let min2 = Infinity, max2 = -Infinity;
    for (let i = 0; i < nums.length - 1; ++i) {
        total += Math.abs(nums[i] - nums[i + 1]);
        min2 = Math.min(min2, Math.max(nums[i], nums[i + 1]));
        max2 = Math.max(max2, Math.min(nums[i], nums[i + 1]));
        diff = Math.max(diff, Math.abs(nums[i + 1] - nums[0]) - Math.abs(nums[i + 1] - nums[i]));
        diff = Math.max(diff, Math.abs(nums[i] - nums[nums.length - 1]) - Math.abs(nums[i] - nums[i + 1]));
    }
    return total + Math.max(diff, 2 * (max2 - min2));
}
```
1. Initialize the required variables for total sum, difference, and minimum and maximum values for further calculations.
2. Iterate through the given array from index 0 to nums.length - 2.
3. Calculate the total sum by adding the absolute difference between nums[i] and nums[i+1].
4. Update the min2 and max2 with the required calculations.
5. Find the maximum possible difference by considering swapping a subarray (0...i+1) or (i...nums.length-1).
6. Return the sum of the total and the maximum value of the calculated difference and 2 times (max2 - min2).


# Encode Number

- slug: encode-number
- difficulty: Medium

Given a non-negative integer `num`, Return its _encoding_ string.

The encoding is done by converting the integer to a string using a secret function that you should deduce from the following table:

**Example 1:**

**Input:** num = 23
**Output:**  "1000 "

**Example 2:**

**Input:** num = 107
**Output:**  "101100 "

**Constraints:**

*   `0 <= num <= 10^9`

\- Rank is an integer starting from 1. - The larger the element, the larger the rank. If two elements are the same, their rank must be the same. - Rank should be as small as possible. Function signature: \`int\[\] arrayRankTransform(int\[\] arr)\`

## A solution in Java

```java
import java.util.Arrays;
import java.util.HashMap;

public int[] arrayRankTransform(int[] arr) {
    int[] sortedArr = arr.clone();
    Arrays.sort(sortedArr);
    HashMap<Integer, Integer> rankMap = new HashMap<>();
    int rank = 1;

    for(int num : sortedArr) {
        if(!rankMap.containsKey(num)) {
            rankMap.put(num, rank++);
        }
    }

    for(int i = 0; i < arr.length; i++) {
        arr[i] = rankMap.get(arr[i]);
    }

    return arr;
}
```
1. Create a new array, `sorted_arr`, that contains the elements of the given `arr` sorted in ascending order.
2. Create a hash map or dictionary, `rank_map`, that will store the rank for each unique integer in the array.
3. Initialize a `rank` variable to 1.
4. Iterate through the sorted array, and for each unique integer not in the `rank_map`, assign its rank and increment the rank counter.
5. Iterate through the original array, replacing each element with its corresponding rank from the `rank_map`.
6. Return the modified array.

## A solution in C++

```cpp
#include <vector>
#include <algorithm>
#include <unordered_map>
using namespace std;

vector<int> arrayRankTransform(vector<int>& arr) {
    vector<int> sorted_arr = arr;
    sort(sorted_arr.begin(), sorted_arr.end());
    unordered_map<int, int> rank_map;
    int rank = 1;

    for(int num : sorted_arr) {
        if(rank_map.find(num) == rank_map.end()) {
            rank_map[num] = rank++;
        }
    }

    for(int i = 0; i < arr.size(); i++) {
        arr[i] = rank_map[arr[i]];
    }

    return arr;
}
```
1. Create a new array, `sorted_arr`, that contains the elements of the given `arr` sorted in ascending order.
2. Create a hash map or dictionary, `rank_map`, that will store the rank for each unique integer in the array.
3. Initialize a `rank` variable to 1.
4. Iterate through the sorted array, and for each unique integer not in the `rank_map`, assign its rank and increment the rank counter.
5. Iterate through the original array, replacing each element with its corresponding rank from the `rank_map`.
6. Return the modified array.

## A solution in Python

```python
def arrayRankTransform(arr):
    sorted_arr = sorted(arr)
    rank_map = {}
    rank = 1

    for num in sorted_arr:
        if num not in rank_map:
            rank_map[num] = rank
            rank += 1

    return [rank_map[num] for num in arr]
```
1. Create a new array, `sorted_arr`, that contains the elements of the given `arr` sorted in ascending order.
2. Create a hash map or dictionary, `rank_map`, that will store the rank for each unique integer in the array.
3. Initialize a `rank` variable to 1.
4. Iterate through the sorted array, and for each unique integer not in the `rank_map`, assign its rank and increment the rank counter.
5. Iterate through the original array, replacing each element with its corresponding rank from the `rank_map`.
6. Return the modified array.

## A solution in Javascript

```javascript
function arrayRankTransform(arr) {
    const sortedArr = [...arr].sort((a, b) => a - b);
    const rankMap = {};
    let rank = 1;

    for(const num of sortedArr) {
        if(!(num in rankMap)) {
            rankMap[num] = rank++;
        }
    }

    return arr.map(num => rankMap[num]);
}
```
1. Create a new array, `sorted_arr`, that contains the elements of the given `arr` sorted in ascending order.
2. Create a hash map or dictionary, `rank_map`, that will store the rank for each unique integer in the array.
3. Initialize a `rank` variable to 1.
4. Iterate through the sorted array, and for each unique integer not in the `rank_map`, assign its rank and increment the rank counter.
5. Iterate through the original array, replacing each element with its corresponding rank from the `rank_map`.
6. Return the modified array.


# Smallest Common Region

- slug: smallest-common-region
- difficulty: Medium

You are given some lists of `regions` where the first region of each list includes all other regions in that list.

Naturally, if a region `x` contains another region `y` then `x` is bigger than `y`. Also, by definition, a region `x` contains itself.

Given two regions: `region1` and `region2`, return _the smallest region that contains both of them_.

If you are given regions `r1`, `r2`, and `r3` such that `r1` includes `r3`, it is guaranteed there is no `r2` such that `r2` includes `r3`.

It is guaranteed the smallest region exists.

**Example 1:**

**Input:**
regions = \[\[ "Earth ", "North America ", "South America "\],
\[ "North America ", "United States ", "Canada "\],
\[ "United States ", "New York ", "Boston "\],
\[ "Canada ", "Ontario ", "Quebec "\],
\[ "South America ", "Brazil "\]\],
region1 =  "Quebec ",
region2 =  "New York "
**Output:**  "North America "

**Example 2:**

**Input:** regions = \[\[ "Earth ",  "North America ",  "South America "\],\[ "North America ",  "United States ",  "Canada "\],\[ "United States ",  "New York ",  "Boston "\],\[ "Canada ",  "Ontario ",  "Quebec "\],\[ "South America ",  "Brazil "\]\], region1 =  "Canada ", region2 =  "South America "
**Output:**  "Earth "

**Constraints:**

*   `2 <= regions.length <= 104`
*   `2 <= regions[i].length <= 20`
*   `1 <= regions[i][j].length, region1.length, region2.length <= 20`
*   `region1 != region2`
*   `regions[i][j]`, `region1`, and `region2` consist of English letters.

## A solution in Java

```java
import java.util.*;
import javafx.util.Pair;
class Solution {
    public int[][] matrixRankTransform(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        int[][] rank = new int[m][n];
        int[] sorted_row = new int[m], sorted_col = new int[n];

        for (int bound=0; bound<=200000; bound++) {
            Queue<Pair<Integer, Integer>> q = new LinkedList<>();
            for (int i = 0; i<m; ++i)
                for (int j = 0; j<n; ++j)
                    if (matrix[i][j] == bound && rank[i][j] == 0) q.add(new Pair<>(i, j));

            if (q.isEmpty()) break;
            for (Pair<Integer, Integer> rc; !q.isEmpty(); q.poll()) {
                int r = rc.getKey();
                int c = rc.getValue();
                int potential_rank = sorted_row[r] + 1;
                for (Pair<Integer, Integer> neighbour: neighbours(r, c, m, n)) {
                    int row = neighbour.getKey();
                    int col = neighbour.getValue();
                    if (matrix[row][col] <= matrix[r][c])
                        potential_rank = Math.max(potential_rank, rank[row][col] + (matrix[row][col] < matrix[r][c] ? 0 : 1));
                }
                if (potential_rank == sorted_col[c] + 1) {
                    rank[r][c] = sorted_row[r] = sorted_col[c] = potential_rank;
                } else {
                    q.add(rc);
                }
            }
        }
        return rank;
    }

    private List<Pair<Integer, Integer>> neighbours(int r, int c, int m, int n) {
        List<Pair<Integer, Integer>> res = new ArrayList<>();
        for (int i=0; i<m; ++i) if (i != r) res.add(new Pair<>(i, c));
        for (int i=0; i<n; ++i) if (i != c) res.add(new Pair<>(r, i));
        return res;
    }
}
```
The algorithm uses a breadth-first search to determine the rank of each element in the given matrix. It maintains rank arrays for each row and column, sorted_row and sorted_col. These arrays store information about the ranks so far, which means while processing elements in the matrix, we can compare them with this rank information to determine their rank.

We use a loop for possible range of values in the matrix (0 to 200,000). Inside the loop, we populate a queue with elements that have their value equal to the current bound and have not been assigned a rank yet. If the queue is empty, we break the loop. Inside this loop for each element, we check its possible rank by looking at its neighboring elements in the corresponding row and column. If the potential_rank obtained is equal to (sorted_col[c] + 1), then we update the rank, sorted_row, and sorted_col arrays.

This process continues until each element has been assigned a rank.

## A solution in C++

```cpp
#include <vector>
#include <queue>

std::vector<std::vector<int>> matrixRankTransform(std::vector<std::vector<int>>& matrix) {
    int m = matrix.size(), n = matrix[0].size();
    std::vector<std::vector<int>> rank(m, std::vector<int>(n));
    std::vector<int> sorted_row(m), sorted_col(n);

    auto neighbours = [&](int r, int c) {
        std::vector<std::pair<int, int>> res;
        for (int i=0; i<m; ++i) if (i != r) res.push_back({i, c});
        for (int i=0; i<n; ++i) if (i != c) res.push_back({r, i});
        return res;
    };

    for (int bound=0; bound<=2e5; bound++) {
        std::queue<std::pair<int, int>> q;
        for (int i = 0; i<m; ++i)
            for (int j = 0; j<n; ++j)
                if (matrix[i][j] == bound && rank[i][j] == 0) q.push({i, j});

        if (q.empty()) break;
        for (std::pair<int, int> rc; !q.empty(); q.pop()) {
            auto [r,c] = rc = q.front();
            int potential_rank = sorted_row[r] + 1;
            for (auto [row, col]: neighbours(r,c))
                if (matrix[row][col] <= matrix[r][c])
                    potential_rank = std::max(potential_rank, rank[row][col] + (matrix[row][col] < matrix[r][c] ? 0 : 1));
            if (potential_rank == sorted_col[c] + 1) {
                rank[r][c] = sorted_row[r] = sorted_col[c] = potential_rank;
            } else {
                q.push(rc);
            }
        }
    }
    return rank;
}
```
The algorithm uses a breadth-first search to determine the rank of each element in the given matrix. It maintains rank arrays for each row and column, sorted_row and sorted_col. These arrays store information about the ranks so far, which means while processing elements in the matrix, we can compare them with this rank information to determine their rank.

We use a loop for possible range of values in the matrix (0 to 200,000). Inside the loop, we populate a queue with elements that have their value equal to the current bound and have not been assigned a rank yet. If the queue is empty, we break the loop. Inside this loop for each element, we check its possible rank by looking at its neighboring elements in the corresponding row and column. If the potential_rank obtained is equal to (sorted_col[c] + 1), then we update the rank, sorted_row, and sorted_col arrays.

This process continues until each element has been assigned a rank.

## A solution in Python

```python
from collections import deque
from itertools import chain

def matrix_rank_transform(matrix):
    def neighbours(r, c):
        for i in range(m):
            if i != r:
                yield i, c
        for i in range(n):
            if i != c:
                yield r, i

    m, n = len(matrix), len(matrix[0])
    rank = [[0] * n for _ in range(m)]
    sorted_row = [0] * m
    sorted_col = [0] * n

    for bound in range(200001):
        q = deque((r, c) for r in range(m) for c in range(n) if matrix[r][c] == bound and rank[r][c] == 0)
        if not q:
            break
        while q:
            r, c = rc = q.popleft()
            potential_rank = sorted_row[r] + 1
            for row, col in neighbours(r, c):
                if matrix[row][col] <= matrix[r][c]:
                    potential_rank = max(potential_rank, rank[row][col] + (matrix[row][col] < matrix[r][c]))
            if potential_rank == sorted_col[c] + 1:
                rank[r][c] = sorted_row[r] = sorted_col[c] = potential_rank
            else:
                q.append(rc)
    return rank
```
The algorithm uses a breadth-first search to determine the rank of each element in the given matrix. It maintains rank arrays for each row and column, sorted_row and sorted_col. These arrays store information about the ranks so far, which means while processing elements in the matrix, we can compare them with this rank information to determine their rank.

We use a loop for possible range of values in the matrix (0 to 200,000). Inside the loop, we populate a queue with elements that have their value equal to the current bound and have not been assigned a rank yet. If the queue is empty, we break the loop. Inside this loop for each element, we check its possible rank by looking at its neighboring elements in the corresponding row and column. If the potential_rank obtained is equal to (sorted_col[c] + 1), then we update the rank, sorted_row, and sorted_col arrays.

This process continues until each element has been assigned a rank.

## A solution in Javascript

```javascript
function matrixRankTransform(matrix) {
    function* neighbours(r, c) {
        for (let i = 0; i < m; ++i) if (i != r) yield [i, c];
        for (let i = 0; i < n; ++i) if (i != c) yield [r, i];
    }

    const m = matrix.length, n = matrix[0].length;
    const rank = Array.from({length: m}, () => Array(n).fill(0));
    const sorted_row = new Array(m).fill(0);
    const sorted_col = new Array(n).fill(0);

    for (let bound = 0; bound <= 200000; bound++) {
        const q = [];
        for (let i = 0; i < m; ++i) {
            for (let j = 0; j < n; ++j) {
                if (matrix[i][j] == bound && rank[i][j] == 0) {
                    q.push([i, j]);
                }
            }
        }
        if (q.length === 0) break;
        while (q.length > 0) {
            const [r, c] = rc = q.shift();
            let potential_rank = sorted_row[r] + 1;
            for (const [row, col] of neighbours(r, c)) {
                if (matrix[row][col] <= matrix[r][c]) {
                    potential_rank = Math.max(potential_rank, rank[row][col] + (matrix[row][col] < matrix[r][c] ? 0 : 1));
                }
            }
            if (potential_rank === (sorted_col[c] + 1)) {
                rank[r][c] = sorted_row[r] = sorted_col[c] = potential_rank;
            } else {
                q.push(rc);
            }
        }
    }
    return rank;
}
```
The algorithm uses a breadth-first search to determine the rank of each element in the given matrix. It maintains rank arrays for each row and column, sorted_row and sorted_col. These arrays store information about the ranks so far, which means while processing elements in the matrix, we can compare them with this rank information to determine their rank.

We use a loop for possible range of values in the matrix (0 to 200,000). Inside the loop, we populate a queue with elements that have their value equal to the current bound and have not been assigned a rank yet. If the queue is empty, we break the loop. Inside this loop for each element, we check its possible rank by looking at its neighboring elements in the corresponding row and column. If the potential_rank obtained is equal to (sorted_col[c] + 1), then we update the rank, sorted_row, and sorted_col arrays.

This process continues until each element has been assigned a rank.


# Synonymous Sentences

- slug: synonymous-sentences
- difficulty: Medium

You are given a list of equivalent string pairs `synonyms` where `synonyms[i] = [si, ti]` indicates that `si` and `ti` are equivalent strings. You are also given a sentence `text`.

Return _all possible synonymous sentences **sorted lexicographically**_.

**Example 1:**

**Input:** synonyms = \[\[ "happy ", "joy "\],\[ "sad ", "sorrow "\],\[ "joy ", "cheerful "\]\], text =  "I am happy today but was sad yesterday "
**Output:** \[ "I am cheerful today but was sad yesterday ", "I am cheerful today but was sorrow yesterday ", "I am happy today but was sad yesterday ", "I am happy today but was sorrow yesterday ", "I am joy today but was sad yesterday ", "I am joy today but was sorrow yesterday "\]

**Example 2:**

**Input:** synonyms = \[\[ "happy ", "joy "\],\[ "cheerful ", "glad "\]\], text =  "I am happy today but was sad yesterday "
**Output:** \[ "I am happy today but was sad yesterday ", "I am joy today but was sad yesterday "\]

**Constraints:**

*   `0 <= synonyms.length <= 10`
*   `synonyms[i].length == 2`
*   `1 <= si.length, ti.length <= 10`
*   `si != ti`
*   `text` consists of at most `10` words.
*   All the pairs of `synonyms` are **unique**.
*   The words of `text` are separated by single spaces.

## A solution in Java

```java
import java.util.*;

public List<String> generateSentences(List<List<String>> synonyms, String text) {
    Map<String, Set<String>> synonymMap = new HashMap<>();

    for (List<String> synPair : synonyms) {
        synonymMap.putIfAbsent(synPair.get(0), new HashSet<>());
        synonymMap.putIfAbsent(synPair.get(1), new HashSet<>());
        synonymMap.get(synPair.get(0)).add(synPair.get(1));
        synonymMap.get(synPair.get(1)).add(synPair.get(0));
    }

    String[] words = text.split(" ");
    List<String> result = new ArrayList<>();
    generateSentencesHelper(0, words, synonymMap, result, new StringBuilder());
    Collections.sort(result);

    return result;
}

private void generateSentencesHelper(int index, String[] words, Map<String, Set<String>> synonyms, List<String> result, StringBuilder curSentence) {
    if (index == words.length) {
        result.add(curSentence.toString());
    } else {
        Set<String> synSet = synonyms.getOrDefault(words[index], new HashSet<>());
        synSet.add(words[index]);

        int prevLength = curSentence.length();
        for (String syn : synSet) {
            if (prevLength > 0) {
                curSentence.append(" ");
            }
            curSentence.append(syn);

            generateSentencesHelper(index + 1, words, synonyms, result, curSentence);

            curSentence.setLength(prevLength);
        }
    }
}
```
1. Build a map (`synonymMap`) for each word in the synonyms list so that we can look up its synonyms easily later.
2. Split the input `text` into a list/array of words.
3. Use a helper function (`generateSentencesHelper` or `helper`) to perform a depth-first search on combining words with their synonyms.
4. The helper function takes the index of the current word being processed, and a current sentence being created as input.
5. If the current index is equal to the length of the words list, we have processed all words, and we can add the current sentence to the result list.
6. If the index is not at the end, we look up synonyms for the current word using the `synonymMap`. If there are no synonyms, we simply add the current word itself to the set.
7. Iterate over the synonyms (including the current word itself), and recursively call the helper function with the next word index, and the current sentence with the appended synonym.
8. After the recursive steps, remove the last word from the current sentence to backtrack.
9. After completing the depth-first search, sort the results list and return it.

## A solution in C++

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

using namespace std;

void generateSentencesHelper(int index, vector<string>& words, map<string, set<string>>& synonyms, vector<string>& result, string curSentence) {
    if (index == words.size()) {
        result.push_back(curSentence);
    } else {
        set<string>& synSet = synonyms[words[index]];
        for (const auto& syn : synSet) {
            generateSentencesHelper(index + 1, words, synonyms, result, curSentence + (curSentence.empty() ? "" : " ") + syn);
        }
    }
}

vector<string> generateSentences(vector<vector<string>>& synonyms, string text) {
    map<string, set<string>> synonymMap;

    for (const auto& synPair : synonyms) {
        synonymMap[synPair[0]].insert(synPair[0]);
        synonymMap[synPair[0]].insert(synPair[1]);
        synonymMap[synPair[1]].insert(synPair[0]);
        synonymMap[synPair[1]].insert(synPair[1]);
    }

    vector<string> words;
    size_t start = 0, end = text.find(' ');

    while (end != string::npos) {
        words.push_back(text.substr(start, end - start));
        start = end + 1;
        end = text.find(' ', start);
    }

    words.push_back(text.substr(start));

    vector<string> result;
    generateSentencesHelper(0, words, synonymMap, result, "");

    return result;
}
```
1. Build a map (`synonymMap`) for each word in the synonyms list so that we can look up its synonyms easily later.
2. Split the input `text` into a list/array of words.
3. Use a helper function (`generateSentencesHelper` or `helper`) to perform a depth-first search on combining words with their synonyms.
4. The helper function takes the index of the current word being processed, and a current sentence being created as input.
5. If the current index is equal to the length of the words list, we have processed all words, and we can add the current sentence to the result list.
6. If the index is not at the end, we look up synonyms for the current word using the `synonymMap`. If there are no synonyms, we simply add the current word itself to the set.
7. Iterate over the synonyms (including the current word itself), and recursively call the helper function with the next word index, and the current sentence with the appended synonym.
8. After the recursive steps, remove the last word from the current sentence to backtrack.
9. After completing the depth-first search, sort the results list and return it.

## A solution in Python

```python
from typing import List

def generateSentences(synonyms: List[List[str]], text: str) -> List[str]:
    synonym_map = {}

    for s, t in synonyms:
        if s not in synonym_map:
            synonym_map[s] = {s}
        if t not in synonym_map:
            synonym_map[t] = {t}
        synonym_map[s].add(t)
        synonym_map[t].add(s)

    words = text.split()
    results = []

    def helper(index: int, cur_sentence: List[str]) -> None:
        if index == len(words):
            results.append(" ".join(cur_sentence))
            return
        for w in synonym_map.get(words[index], {words[index]}):
            cur_sentence.append(w)
            helper(index + 1, cur_sentence)
            cur_sentence.pop()

    helper(0, [])

    return sorted(results)
```
1. Build a map (`synonymMap`) for each word in the synonyms list so that we can look up its synonyms easily later.
2. Split the input `text` into a list/array of words.
3. Use a helper function (`generateSentencesHelper` or `helper`) to perform a depth-first search on combining words with their synonyms.
4. The helper function takes the index of the current word being processed, and a current sentence being created as input.
5. If the current index is equal to the length of the words list, we have processed all words, and we can add the current sentence to the result list.
6. If the index is not at the end, we look up synonyms for the current word using the `synonymMap`. If there are no synonyms, we simply add the current word itself to the set.
7. Iterate over the synonyms (including the current word itself), and recursively call the helper function with the next word index, and the current sentence with the appended synonym.
8. After the recursive steps, remove the last word from the current sentence to backtrack.
9. After completing the depth-first search, sort the results list and return it.

## A solution in Javascript

```javascript
function generateSentences(synonyms, text) {
    const synonymMap = new Map();

    for (const [s, t] of synonyms) {
        if (!synonymMap.has(s)) {
            synonymMap.set(s, new Set([s]));
        }
        if (!synonymMap.has(t)) {
            synonymMap.set(t, new Set([t]));
        }
        synonymMap.get(s).add(t);
        synonymMap.get(t).add(s);
    }

    const words = text.split(" ");
    const results = [];

    function helper(index, curSentence) {
        if (index === words.length) {
            results.push(curSentence.join(" "));
        } else {
            const synSet = synonymMap.get(words[index]) || new Set([words[index]]);

            for (const w of synSet) {
                curSentence.push(w);
                helper(index + 1, curSentence);
                curSentence.pop();
            }
        }
    }

    helper(0, []);

    return results.sort();
}
```
1. Build a map (`synonymMap`) for each word in the synonyms list so that we can look up its synonyms easily later.
2. Split the input `text` into a list/array of words.
3. Use a helper function (`generateSentencesHelper` or `helper`) to perform a depth-first search on combining words with their synonyms.
4. The helper function takes the index of the current word being processed, and a current sentence being created as input.
5. If the current index is equal to the length of the words list, we have processed all words, and we can add the current sentence to the result list.
6. If the index is not at the end, we look up synonyms for the current word using the `synonymMap`. If there are no synonyms, we simply add the current word itself to the set.
7. Iterate over the synonyms (including the current word itself), and recursively call the helper function with the next word index, and the current sentence with the appended synonym.
8. After the recursive steps, remove the last word from the current sentence to backtrack.
9. After completing the depth-first search, sort the results list and return it.


# Handshakes That Don't Cross

- slug: handshakes-that-dont-cross
- difficulty: Hard

You are given an **even** number of people `numPeople` that stand around a circle and each person shakes hands with someone else so that there are `numPeople / 2` handshakes total.

Return _the number of ways these handshakes could occur such that none of the handshakes cross_.

Since the answer could be very large, return it **modulo** `109 + 7`.

**Example 1:**

**Input:** numPeople = 4
**Output:** 2
**Explanation:** There are two ways to do it, the first way is \[(1,2),(3,4)\] and the second one is \[(2,3),(4,1)\].

**Example 2:**

**Input:** numPeople = 6
**Output:** 5

**Constraints:**

*   `2 <= numPeople <= 1000`
*   `numPeople` is even.

## A solution in Java

```java
public int numberOfWays(int numPeople) {
    int MOD = 1000000007;
    int[] dp = new int[numPeople / 2 + 1];
    dp[0] = 1;
    for (int i = 1; i <= numPeople / 2; ++i) {
        for (int j = 1; j <= i; ++j) {
            dp[i] = (dp[i] + (int)(((long) dp[i - j] * dp[j - 1]) % MOD )) % MOD;
        }
    }
    return dp[numPeople / 2];
}
```
The problem can be solved using dynamic programming. We can use dp[i] to represent the number of different ways i pairs of people can perform handshakes without crossing. We initialize dp[0] to 1 as there is one way to perform no handshakes.

Now, we iterate from 1 to numPeople/2 inclusive. In each iteration, we consider one pair of people at a time. Suppose there are i pairs of people and the current pair to be considered is j. Then, the remaining pairs of people can be divided into two groups - one having j - 1 pairs and the other having i - j pairs. Thus, we can calculate dp[i] by using the previous values of dp[]. Specifically, dp[i] is updated as follows:
dp[i] = (dp[i] + (dp[i - j] * dp[j - 1]) % MOD) % MOD;

Finally, we return dp[numPeople / 2].

## A solution in C++

```cpp
int numberOfWays(int numPeople) {
    const int MOD = 1000000007;
    vector<int> dp(numPeople / 2 + 1);
    dp[0] = 1;
    for (int i = 1; i <= numPeople / 2; ++i) {
        for (int j = 1; j <= i; ++j) {
            dp[i] = (dp[i] + ((long long) dp[i - j] * dp[j - 1]) % MOD) % MOD;
        }
    }
    return dp[numPeople / 2];
}
```
The problem can be solved using dynamic programming. We can use dp[i] to represent the number of different ways i pairs of people can perform handshakes without crossing. We initialize dp[0] to 1 as there is one way to perform no handshakes.

Now, we iterate from 1 to numPeople/2 inclusive. In each iteration, we consider one pair of people at a time. Suppose there are i pairs of people and the current pair to be considered is j. Then, the remaining pairs of people can be divided into two groups - one having j - 1 pairs and the other having i - j pairs. Thus, we can calculate dp[i] by using the previous values of dp[]. Specifically, dp[i] is updated as follows:
dp[i] = (dp[i] + (dp[i - j] * dp[j - 1]) % MOD) % MOD;

Finally, we return dp[numPeople / 2].

## A solution in Python

```python
def numberOfWays(numPeople: int) -> int:
    MOD = 1000000007
    dp = [0] * (numPeople // 2 + 1)
    dp[0] = 1
    for i in range(1, numPeople // 2 + 1):
        for j in range(1, i + 1):
            dp[i] = (dp[i] + dp[i - j] * dp[j - 1]) % MOD
    return dp[numPeople // 2]
```
The problem can be solved using dynamic programming. We can use dp[i] to represent the number of different ways i pairs of people can perform handshakes without crossing. We initialize dp[0] to 1 as there is one way to perform no handshakes.

Now, we iterate from 1 to numPeople/2 inclusive. In each iteration, we consider one pair of people at a time. Suppose there are i pairs of people and the current pair to be considered is j. Then, the remaining pairs of people can be divided into two groups - one having j - 1 pairs and the other having i - j pairs. Thus, we can calculate dp[i] by using the previous values of dp[]. Specifically, dp[i] is updated as follows:
dp[i] = (dp[i] + (dp[i - j] * dp[j - 1]) % MOD) % MOD;

Finally, we return dp[numPeople / 2].

## A solution in Javascript

```javascript
function numberOfWays(numPeople) {
    const MOD = 1000000007;
    let dp = new Array(numPeople / 2 + 1).fill(0);
    dp[0] = 1;
    for (let i = 1; i <= numPeople / 2; ++i) {
        for (let j = 1; j <= i; ++j) {
            dp[i] = (dp[i] + (dp[i - j] * dp[j - 1]) % MOD) % MOD;
        }
    }
    return dp[numPeople / 2];
}
```
The problem can be solved using dynamic programming. We can use dp[i] to represent the number of different ways i pairs of people can perform handshakes without crossing. We initialize dp[0] to 1 as there is one way to perform no handshakes.

Now, we iterate from 1 to numPeople/2 inclusive. In each iteration, we consider one pair of people at a time. Suppose there are i pairs of people and the current pair to be considered is j. Then, the remaining pairs of people can be divided into two groups - one having j - 1 pairs and the other having i - j pairs. Thus, we can calculate dp[i] by using the previous values of dp[]. Specifically, dp[i] is updated as follows:
dp[i] = (dp[i] + (dp[i - j] * dp[j - 1]) % MOD) % MOD;

Finally, we return dp[numPeople / 2].


# Shift 2D Grid

- slug: shift-2d-grid
- difficulty: Easy

Given a 2D `grid` of size `m x n` and an integer `k`. You need to shift the `grid` `k` times.

In one shift operation:

*   Element at `grid[i][j]` moves to `grid[i][j + 1]`.
*   Element at `grid[i][n - 1]` moves to `grid[i + 1][0]`.
*   Element at `grid[m - 1][n - 1]` moves to `grid[0][0]`.

Return the _2D grid_ after applying shift operation `k` times.

**Example 1:**

**Input:** `grid` = \[\[1,2,3\],\[4,5,6\],\[7,8,9\]\], k = 1
**Output:** \[\[9,1,2\],\[3,4,5\],\[6,7,8\]\]

**Example 2:**

**Input:** `grid` = \[\[3,8,1,9\],\[19,7,2,5\],\[4,6,11,10\],\[12,0,21,13\]\], k = 4
**Output:** \[\[12,0,21,13\],\[3,8,1,9\],\[19,7,2,5\],\[4,6,11,10\]\]

**Example 3:**

**Input:** `grid` = \[\[1,2,3\],\[4,5,6\],\[7,8,9\]\], k = 9
**Output:** \[\[1,2,3\],\[4,5,6\],\[7,8,9\]\]

**Constraints:**

*   `m == grid.length`
*   `n == grid[i].length`
*   `1 <= m <= 50`
*   `1 <= n <= 50`
*   `-1000 <= grid[i][j] <= 1000`
*   `0 <= k <= 100`

## A solution in Java

```java
public int dayOfYear(String date) {
    int year = Integer.parseInt(date.substring(0, 4));
    int month = Integer.parseInt(date.substring(5, 7));
    int day = Integer.parseInt(date.substring(8, 10));

    int[] daysInMonth = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
        daysInMonth[2] = 29;
    }

    int dayOfYear = 0;
    for (int i = 1; i < month; i++) {
        dayOfYear += daysInMonth[i];
    }
    dayOfYear += day;

    return dayOfYear;
}
```
1. Parse the input string to extract the year, month, and day as integers.
2. Create an array `daysInMonth` representing the days in each month, with a special case for February in leap years.
3. Iterate through the `daysInMonth` array up to the given month, accumulating the days in each month.
4. Add the given day to the accumulated days to get the day number of the year.
5. Return the resulting day number of the year.

## A solution in C++

```cpp
int dayOfYear(std::string date) {
    int year = stoi(date.substr(0, 4));
    int month = stoi(date.substr(5, 2));
    int day = stoi(date.substr(8, 2));

    int daysInMonth[] = {0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
    if (year % 4 == 0 && (year % 100 != 0 || year % 400 == 0)) {
        daysInMonth[2] = 29;
    }

    int dayOfYear = 0;
    for (int i = 1; i < month; ++i) {
        dayOfYear += daysInMonth[i];
    }
    dayOfYear += day;

    return dayOfYear;
}
```
1. Parse the input string to extract the year, month, and day as integers.
2. Create an array `daysInMonth` representing the days in each month, with a special case for February in leap years.
3. Iterate through the `daysInMonth` array up to the given month, accumulating the days in each month.
4. Add the given day to the accumulated days to get the day number of the year.
5. Return the resulting day number of the year.

## A solution in Python

```python
def dayOfYear(date: str) -> int:
    year, month, day = map(int, date.split('-'))

    daysInMonth = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31]
    if year % 4 == 0 and (year % 100 != 0 or year % 400 == 0):
        daysInMonth[2] = 29

    dayOfYear = sum(daysInMonth[:month]) + day
    return dayOfYear
```
1. Parse the input string to extract the year, month, and day as integers.
2. Create an array `daysInMonth` representing the days in each month, with a special case for February in leap years.
3. Iterate through the `daysInMonth` array up to the given month, accumulating the days in each month.
4. Add the given day to the accumulated days to get the day number of the year.
5. Return the resulting day number of the year.

## A solution in Javascript

```javascript
function dayOfYear(date) {
    let [year, month, day] = date.split('-').map(x => parseInt(x, 10));

    let daysInMonth = [0, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31];
    if (year % 4 === 0 && (year % 100 !== 0 || year % 400 === 0)) {
        daysInMonth[2] = 29;
    }

    let dayOfYear = 0;
    for (let i = 1; i < month; i++) {
        dayOfYear += daysInMonth[i];
    }
    dayOfYear += day;

    return dayOfYear;
}
```
1. Parse the input string to extract the year, month, and day as integers.
2. Create an array `daysInMonth` representing the days in each month, with a special case for February in leap years.
3. Iterate through the `daysInMonth` array up to the given month, accumulating the days in each month.
4. Add the given day to the accumulated days to get the day number of the year.
5. Return the resulting day number of the year.


# Find Elements in a Contaminated Binary Tree

- slug: find-elements-in-a-contaminated-binary-tree
- difficulty: Medium

Given a binary tree with the following rules:

1.  `root.val == 0`
2.  If `treeNode.val == x` and `treeNode.left != null`, then `treeNode.left.val == 2 * x + 1`
3.  If `treeNode.val == x` and `treeNode.right != null`, then `treeNode.right.val == 2 * x + 2`

Now the binary tree is contaminated, which means all `treeNode.val` have been changed to `-1`.

Implement the `FindElements` class:

*   `FindElements(TreeNode* root)` Initializes the object with a contaminated binary tree and recovers it.
*   `bool find(int target)` Returns `true` if the `target` value exists in the recovered binary tree.

**Example 1:**

**Input**
\[ "FindElements ", "find ", "find "\]
\[\[\[-1,null,-1\]\],\[1\],\[2\]\]
**Output**
\[null,false,true\]
**Explanation**
FindElements findElements = new FindElements(\[-1,null,-1\]);
findElements.find(1); // return False
findElements.find(2); // return True

**Example 2:**

**Input**
\[ "FindElements ", "find ", "find ", "find "\]
\[\[\[-1,-1,-1,-1,-1\]\],\[1\],\[3\],\[5\]\]
**Output**
\[null,true,true,false\]
**Explanation**
FindElements findElements = new FindElements(\[-1,-1,-1,-1,-1\]);
findElements.find(1); // return True
findElements.find(3); // return True
findElements.find(5); // return False

**Example 3:**

**Input**
\[ "FindElements ", "find ", "find ", "find ", "find "\]
\[\[\[-1,null,-1,-1,null,-1\]\],\[2\],\[3\],\[4\],\[5\]\]
**Output**
\[null,true,false,false,true\]
**Explanation**
FindElements findElements = new FindElements(\[-1,null,-1,-1,null,-1\]);
findElements.find(2); // return True
findElements.find(3); // return False
findElements.find(4); // return False
findElements.find(5); // return True

**Constraints:**

*   `TreeNode.val == -1`
*   The height of the binary tree is less than or equal to `20`
*   The total number of nodes is between `[1, 104]`
*   Total calls of `find()` is between `[1, 104]`
*   `0 <= target <= 106`

## A solution in Java

```java
import java.util.HashSet;
import java.util.Set;

class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
}

class FindElements {
    Set<Integer> values;

    public FindElements(TreeNode root) {
        values = new HashSet<>();
        recoverTree(root, 0);
    }

    public boolean find(int target) {
        return values.contains(target);
    }

    private void recoverTree(TreeNode node, int val) {
        if (node == null) return;

        node.val = val;
        values.add(val);

        recoverTree(node.left, val * 2 + 1);
        recoverTree(node.right, val * 2 + 2);
    }
}
```
The main idea of the solution is to recover the tree by assigning appropriate values based on the given rules and storing them in a set (`values`). When finding the target value, we simply check if it exists in the set or not.

In the constructor, we call the `recoverTree()` function which takes a tree node and value as parameters. This function is designed to traverse the tree recursively and assign correct values to the tree nodes.

In the recoverTree() function, if the passed node is null, then we simply return. Otherwise, we assign the provided value `val` to the node and add it to the set `values`. After that, we make recursive calls to recoverTree() for left and right children of the node with updated values according to the given rules (val * 2 + 1 for left child and val * 2 + 2 for right child).

The find() function checks if the target value exists in the `values` set, returning true if it exists, and false otherwise.

## A solution in C++

```cpp
struct TreeNode {
    int val;
    TreeNode* left;
    TreeNode* right;
};

class FindElements {
public:
    FindElements(TreeNode* root) {
        recoverTree(root, 0);
    }

    bool find(int target) {
        return values.find(target) != values.end();
    }

private:
    void recoverTree(TreeNode* node, int val) {
        if (node == nullptr) return;

        node->val = val;
        values.insert(val);

        recoverTree(node->left, val * 2 + 1);
        recoverTree(node->right, val * 2 + 2);
    }

    std::set<int> values;
};
```
The main idea of the solution is to recover the tree by assigning appropriate values based on the given rules and storing them in a set (`values`). When finding the target value, we simply check if it exists in the set or not.

In the constructor, we call the `recoverTree()` function which takes a tree node and value as parameters. This function is designed to traverse the tree recursively and assign correct values to the tree nodes.

In the recoverTree() function, if the passed node is null, then we simply return. Otherwise, we assign the provided value `val` to the node and add it to the set `values`. After that, we make recursive calls to recoverTree() for left and right children of the node with updated values according to the given rules (val * 2 + 1 for left child and val * 2 + 2 for right child).

The find() function checks if the target value exists in the `values` set, returning true if it exists, and false otherwise.

## 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

class FindElements:
    def __init__(self, root: TreeNode):
        self.values = set()
        self.recoverTree(root, 0)

    def find(self, target: int) -> bool:
        return target in self.values

    def recoverTree(self, node: TreeNode, val: int):
        if node is None:
            return

        node.val = val
        self.values.add(val)

        self.recoverTree(node.left, val * 2 + 1)
        self.recoverTree(node.right, val * 2 + 2)
```
The main idea of the solution is to recover the tree by assigning appropriate values based on the given rules and storing them in a set (`values`). When finding the target value, we simply check if it exists in the set or not.

In the constructor, we call the `recoverTree()` function which takes a tree node and value as parameters. This function is designed to traverse the tree recursively and assign correct values to the tree nodes.

In the recoverTree() function, if the passed node is null, then we simply return. Otherwise, we assign the provided value `val` to the node and add it to the set `values`. After that, we make recursive calls to recoverTree() for left and right children of the node with updated values according to the given rules (val * 2 + 1 for left child and val * 2 + 2 for right child).

The find() function checks if the target value exists in the `values` set, returning true if it exists, and false otherwise.

## A solution in Javascript

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

class FindElements {
    constructor(root) {
        this.values = new Set();
        this.recoverTree(root, 0);
    }

    find(target) {
        return this.values.has(target);
    }

    recoverTree(node, val) {
        if (node === null) return;

        node.val = val;
        this.values.add(val);

        this.recoverTree(node.left, val * 2 + 1);
        this.recoverTree(node.right, val * 2 + 2);
    }
}
```
The main idea of the solution is to recover the tree by assigning appropriate values based on the given rules and storing them in a set (`values`). When finding the target value, we simply check if it exists in the set or not.

In the constructor, we call the `recoverTree()` function which takes a tree node and value as parameters. This function is designed to traverse the tree recursively and assign correct values to the tree nodes.

In the recoverTree() function, if the passed node is null, then we simply return. Otherwise, we assign the provided value `val` to the node and add it to the set `values`. After that, we make recursive calls to recoverTree() for left and right children of the node with updated values according to the given rules (val * 2 + 1 for left child and val * 2 + 2 for right child).

The find() function checks if the target value exists in the `values` set, returning true if it exists, and false otherwise.


# Greatest Sum Divisible by Three

- slug: greatest-sum-divisible-by-three
- difficulty: Medium

Given an integer array `nums`, return _the **maximum possible sum** of elements of the array such that it is divisible by three_.

**Example 1:**

**Input:** nums = \[3,6,5,1,8\]
**Output:** 18
**Explanation:** Pick numbers 3, 6, 1 and 8 their sum is 18 (maximum sum divisible by 3).

**Example 2:**

**Input:** nums = \[4\]
**Output:** 0
**Explanation:** Since 4 is not divisible by 3, do not pick any number.

**Example 3:**

**Input:** nums = \[1,2,3,4,4\]
**Output:** 12
**Explanation:** Pick numbers 1, 3, 4 and 4 their sum is 12 (maximum sum divisible by 3).

**Constraints:**

*   `1 <= nums.length <= 4 * 104`
*   `1 <= nums[i] <= 104`

## A solution in Java

```java
import java.util.*;

class MajorityChecker {
    Map<Integer, List<Integer>> positions;
    int[] arr;

    public MajorityChecker(int[] arr) {
        this.arr = arr;
        positions = new HashMap<>();
        for(int i = 0; i < arr.length; i++) {
            positions.computeIfAbsent(arr[i], x -> new ArrayList<>()).add(i);
        }
    }

    public int query(int left, int right, int threshold) {
        Random rnd = new Random();
        for(int i = 0; i < 20; i++) {
            int randomIndex = rnd.nextInt(right - left + 1) + left;
            int num = positions.get(arr[randomIndex]).size();
            if (num >= threshold) {
                int lb = Collections.binarySearch(positions.get(arr[randomIndex]), left);
                int ub = Collections.binarySearch(positions.get(arr[randomIndex]), right + 1);
                if(lb < 0) lb = ~lb;
                if(ub < 0) ub = ~ub;
                if(ub - lb >= threshold) return arr[randomIndex];
            }
        }
        return -1;
    }
}
```
The MajorityChecker class utilizes an unordered_map (in C++) / HashMap (in Java) / defaultdict (in Python) / Map (in JS) to store the positions of each element in the array. When initializing the class, the positions map is built accordingly. When querying the majority element, we use the Boyer-Moore Majority Vote algorithm with randomization:

1. Select a random index within the range of the subarray.
2. Check if the selected element occurs threshold times or more in the whole array (using the size of the stored positions).
3. If it occurs threshold times or more, check if it occurs threshold times or more in the subarray (using the lower_bound and upper_bound functions).
4. If it occurs threshold times or more within the subarray, return the element as majority.
5. Repeat steps 1-4 for 20 iterations. If no majority element is found, return -1 as no majority found.

The lower_bound and upper_bound functions help to find the first index at which the target is greater than or equal to the existing element and the first index which is greater than the target, respectively.

The algorithm works effectively as the majority element occurs more than half of the times, so the probability of picking it randomly in the 20 iterations is very high.

## A solution in C++

```cpp
class MajorityChecker {
public:
    MajorityChecker(vector<int>& arr) {
        for(int i = 0; i < arr.size(); i++) {
            positions[arr[i]].push_back(i);
        }
    }

    int query(int left, int right, int threshold) {
        for(int i = 0; i < 20; i++) {
            int randomIndex = rand() % (right - left + 1) + left;
            int num = positions[arr[randomIndex]].size();
            if (num >= threshold) {
                auto lb = lower_bound(positions[arr[randomIndex]].begin(), positions[arr[randomIndex]].end(), left);
                auto ub = upper_bound(positions[arr[randomIndex]].begin(), positions[arr[randomIndex]].end(), right);
                if(ub - lb >= threshold) return arr[randomIndex];
            }
        }
        return -1;
    }
private:
    unordered_map<int, vector<int>> positions;
};
```
The MajorityChecker class utilizes an unordered_map (in C++) / HashMap (in Java) / defaultdict (in Python) / Map (in JS) to store the positions of each element in the array. When initializing the class, the positions map is built accordingly. When querying the majority element, we use the Boyer-Moore Majority Vote algorithm with randomization:

1. Select a random index within the range of the subarray.
2. Check if the selected element occurs threshold times or more in the whole array (using the size of the stored positions).
3. If it occurs threshold times or more, check if it occurs threshold times or more in the subarray (using the lower_bound and upper_bound functions).
4. If it occurs threshold times or more within the subarray, return the element as majority.
5. Repeat steps 1-4 for 20 iterations. If no majority element is found, return -1 as no majority found.

The lower_bound and upper_bound functions help to find the first index at which the target is greater than or equal to the existing element and the first index which is greater than the target, respectively.

The algorithm works effectively as the majority element occurs more than half of the times, so the probability of picking it randomly in the 20 iterations is very high.

## A solution in Python

```python
from collections import defaultdict
from random import randint

class MajorityChecker:
    def __init__(self, arr: List[int]):
        self.arr = arr
        self.positions = defaultdict(list)
        for i, num in enumerate(arr):
            self.positions[num].append(i)

    def query(self, left: int, right: int, threshold: int) -> int:
        for _ in range(20):
            randomIndex = randint(left, right)
            num = self.arr[randomIndex]
            lb = self.lower_bound(self.positions[num], left)
            ub = self.upper_bound(self.positions[num], right)
            if ub - lb >= threshold:
                return num
        return -1

    def lower_bound(self, nums, target):
        l, r = 0, len(nums)
        while l < r:
            mid = (l + r) // 2
            if nums[mid] < target:
                l = mid + 1
            else:
                r = mid
        return l

    def upper_bound(self, nums, target):
        l, r = 0, len(nums)
        while l < r:
            mid = (l + r) // 2
            if nums[mid] <= target:
                l = mid + 1
            else:
                r = mid
        return l
```
The MajorityChecker class utilizes an unordered_map (in C++) / HashMap (in Java) / defaultdict (in Python) / Map (in JS) to store the positions of each element in the array. When initializing the class, the positions map is built accordingly. When querying the majority element, we use the Boyer-Moore Majority Vote algorithm with randomization:

1. Select a random index within the range of the subarray.
2. Check if the selected element occurs threshold times or more in the whole array (using the size of the stored positions).
3. If it occurs threshold times or more, check if it occurs threshold times or more in the subarray (using the lower_bound and upper_bound functions).
4. If it occurs threshold times or more within the subarray, return the element as majority.
5. Repeat steps 1-4 for 20 iterations. If no majority element is found, return -1 as no majority found.

The lower_bound and upper_bound functions help to find the first index at which the target is greater than or equal to the existing element and the first index which is greater than the target, respectively.

The algorithm works effectively as the majority element occurs more than half of the times, so the probability of picking it randomly in the 20 iterations is very high.

## A solution in Javascript

```javascript
class MajorityChecker {
    constructor(arr) {
        this.arr = arr;
        this.positions = new Map();
        for(let i = 0; i < arr.length; i++) {
            if (!this.positions.has(arr[i])) this.positions.set(arr[i], []);
            this.positions.get(arr[i]).push(i);
        }
    }

    query(left, right, threshold) {
        for(let i = 0; i < 20; i++) {
            let randomIndex = Math.floor(Math.random() * (right - left + 1)) + left;
            let num = this.positions.get(this.arr[randomIndex]).length;
            if (num >= threshold) {
                let lb = this.lower_bound(this.positions.get(this.arr[randomIndex]), left);
                let ub = this.upper_bound(this.positions.get(this.arr[randomIndex]), right);
                if(ub - lb >= threshold) return this.arr[randomIndex];
            }
        }
        return -1;
    }

    lower_bound(nums, target) {
        let l = 0, r = nums.length;
        while (l < r) {
            let mid = Math.floor((l + r) / 2);
            if (nums[mid] < target) l = mid + 1;
            else r = mid;
        }
        return l;
    }

    upper_bound(nums, target) {
        let l = 0, r = nums.length;
        while (l < r) {
            let mid = Math.floor((l + r) / 2);
            if (nums[mid] <= target) l = mid + 1;
            else r = mid;
        }
        return l;
    }
}
```
The MajorityChecker class utilizes an unordered_map (in C++) / HashMap (in Java) / defaultdict (in Python) / Map (in JS) to store the positions of each element in the array. When initializing the class, the positions map is built accordingly. When querying the majority element, we use the Boyer-Moore Majority Vote algorithm with randomization:

1. Select a random index within the range of the subarray.
2. Check if the selected element occurs threshold times or more in the whole array (using the size of the stored positions).
3. If it occurs threshold times or more, check if it occurs threshold times or more in the subarray (using the lower_bound and upper_bound functions).
4. If it occurs threshold times or more within the subarray, return the element as majority.
5. Repeat steps 1-4 for 20 iterations. If no majority element is found, return -1 as no majority found.

The lower_bound and upper_bound functions help to find the first index at which the target is greater than or equal to the existing element and the first index which is greater than the target, respectively.

The algorithm works effectively as the majority element occurs more than half of the times, so the probability of picking it randomly in the 20 iterations is very high.


# Minimum Moves to Move a Box to Their Target Location

- slug: minimum-moves-to-move-a-box-to-their-target-location
- difficulty: Hard

A storekeeper is a game in which the player pushes boxes around in a warehouse trying to get them to target locations.

The game is represented by an `m x n` grid of characters `grid` where each element is a wall, floor, or box.

Your task is to move the box `'B'` to the target position `'T'` under the following rules:

*   The character `'S'` represents the player. The player can move up, down, left, right in `grid` if it is a floor (empty cell).
*   The character `'.'` represents the floor which means a free cell to walk.
*   The character `'#'` represents the wall which means an obstacle (impossible to walk there).
*   There is only one box `'B'` and one target cell `'T'` in the `grid`.
*   The box can be moved to an adjacent free cell by standing next to the box and then moving in the direction of the box. This is a **push**.
*   The player cannot walk through the box.

Return _the minimum number of **pushes** to move the box to the target_. If there is no way to reach the target, return `-1`.

**Example 1:**

**Input:** grid = \[\[ "# ", "# ", "# ", "# ", "# ", "# "\],
               \[ "# ", "T ", "# ", "# ", "# ", "# "\],
               \[ "# ", ". ", ". ", "B ", ". ", "# "\],
               \[ "# ", ". ", "# ", "# ", ". ", "# "\],
               \[ "# ", ". ", ". ", ". ", "S ", "# "\],
               \[ "# ", "# ", "# ", "# ", "# ", "# "\]\]
**Output:** 3
**Explanation:** We return only the number of times the box is pushed.

**Example 2:**

**Input:** grid = \[\[ "# ", "# ", "# ", "# ", "# ", "# "\],
               \[ "# ", "T ", "# ", "# ", "# ", "# "\],
               \[ "# ", ". ", ". ", "B ", ". ", "# "\],
               \[ "# ", "# ", "# ", "# ", ". ", "# "\],
               \[ "# ", ". ", ". ", ". ", "S ", "# "\],
               \[ "# ", "# ", "# ", "# ", "# ", "# "\]\]
**Output:** -1

**Example 3:**

**Input:** grid = \[\[ "# ", "# ", "# ", "# ", "# ", "# "\],
               \[ "# ", "T ", ". ", ". ", "# ", "# "\],
               \[ "# ", ". ", "# ", "B ", ". ", "# "\],
               \[ "# ", ". ", ". ", ". ", ". ", "# "\],
               \[ "# ", ". ", ". ", ". ", "S ", "# "\],
               \[ "# ", "# ", "# ", "# ", "# ", "# "\]\]
**Output:** 5
**Explanation:** push the box down, left, left, up and up.

**Constraints:**

*   `m == grid.length`
*   `n == grid[i].length`
*   `1 <= m, n <= 20`
*   `grid` contains only characters `'.'`, `'#'`, `'S'`, `'T'`, or `'B'`.
*   There is only one character `'S'`, `'B'`, and `'T'` in the `grid`.

## A solution in Java

```java
public int numRollsToTarget(int n, int k, int target) {
    final int MOD = 1000000007;
    int[][] dp = new int[n+1][target+1];
    dp[0][0] = 1;

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= target; ++j) {
            for (int l = 1; l <= k; ++l) {
                if (j >= l) {
                    dp[i][j] = (dp[i][j] + dp[i - 1][j - l]) % MOD;
                }
            }
        }
    }
    return dp[n][target];
}
```
The algorithm uses dynamic programming to find the number of ways to attain the target sum with given `n` dice and `k` faces. We create a 2-D array `dp` where `dp[i][j]` represents the number of ways to reach a sum of `j` using `i` dice.

We initialize `dp[0][0] = 1` since there's only one way to get a sum of zero using zero dice (by rolling no dice). We iterate through `i` from 1 to `n`, `j` from 1 to `target`, and `l` from 1 to `k`. If the current sum `j` is greater than or equal to the current face value `l`, we update the value in `dp[i][j]` as `(dp[i][j] + dp[i - 1][j - l]) % MOD`.

Finally, we return `dp[n][target]` which gives the number of ways to attain the target sum with given `n` dice and `k` faces.

## A solution in C++

```cpp
int numRollsToTarget(int n, int k, int target) {
    const int MOD = 1e9 + 7;
    vector<vector<int>> dp(n + 1, vector<int>(target + 1, 0));
    dp[0][0] = 1;

    for (int i = 1; i <= n; ++i) {
        for (int j = 1; j <= target; ++j) {
            for (int l = 1; l <= k; ++l) {
                if (j >= l) {
                    dp[i][j] = (dp[i][j] + dp[i - 1][j - l]) % MOD;
                }
            }
        }
    }
    return dp[n][target];
}
```
The algorithm uses dynamic programming to find the number of ways to attain the target sum with given `n` dice and `k` faces. We create a 2-D array `dp` where `dp[i][j]` represents the number of ways to reach a sum of `j` using `i` dice.

We initialize `dp[0][0] = 1` since there's only one way to get a sum of zero using zero dice (by rolling no dice). We iterate through `i` from 1 to `n`, `j` from 1 to `target`, and `l` from 1 to `k`. If the current sum `j` is greater than or equal to the current face value `l`, we update the value in `dp[i][j]` as `(dp[i][j] + dp[i - 1][j - l]) % MOD`.

Finally, we return `dp[n][target]` which gives the number of ways to attain the target sum with given `n` dice and `k` faces.

## A solution in Python

```python
def numRollsToTarget(n, k, target):
    MOD = 10**9 + 7
    dp = [[0] * (target + 1) for _ in range(n + 1)]
    dp[0][0] = 1

    for i in range(1, n + 1):
        for j in range(1, target + 1):
            for l in range(1, k + 1):
                if j >= l:
                    dp[i][j] = (dp[i][j] + dp[i - 1][j - l]) % MOD
    return dp[n][target]
```
The algorithm uses dynamic programming to find the number of ways to attain the target sum with given `n` dice and `k` faces. We create a 2-D array `dp` where `dp[i][j]` represents the number of ways to reach a sum of `j` using `i` dice.

We initialize `dp[0][0] = 1` since there's only one way to get a sum of zero using zero dice (by rolling no dice). We iterate through `i` from 1 to `n`, `j` from 1 to `target`, and `l` from 1 to `k`. If the current sum `j` is greater than or equal to the current face value `l`, we update the value in `dp[i][j]` as `(dp[i][j] + dp[i - 1][j - l]) % MOD`.

Finally, we return `dp[n][target]` which gives the number of ways to attain the target sum with given `n` dice and `k` faces.

## A solution in Javascript

```javascript
function numRollsToTarget(n, k, target) {
    const MOD = 1e9 + 7;
    let dp = Array.from({ length: n + 1 }, () => Array(target + 1).fill(0));
    dp[0][0] = 1;

    for (let i = 1; i <= n; ++i) {
        for (let j = 1; j <= target; ++j) {
            for (let l = 1; l <= k; ++l) {
                if (j >= l) {
                    dp[i][j] = (dp[i][j] + dp[i - 1][j - l]) % MOD;
                }
            }
        }
    }
    return dp[n][target];
}
```
The algorithm uses dynamic programming to find the number of ways to attain the target sum with given `n` dice and `k` faces. We create a 2-D array `dp` where `dp[i][j]` represents the number of ways to reach a sum of `j` using `i` dice.

We initialize `dp[0][0] = 1` since there's only one way to get a sum of zero using zero dice (by rolling no dice). We iterate through `i` from 1 to `n`, `j` from 1 to `target`, and `l` from 1 to `k`. If the current sum `j` is greater than or equal to the current face value `l`, we update the value in `dp[i][j]` as `(dp[i][j] + dp[i - 1][j - l]) % MOD`.

Finally, we return `dp[n][target]` which gives the number of ways to attain the target sum with given `n` dice and `k` faces.


# Print Immutable Linked List in Reverse

- slug: print-immutable-linked-list-in-reverse
- difficulty: Medium

You are given an immutable linked list, print out all values of each node in reverse with the help of the following interface:

*   `ImmutableListNode`: An interface of immutable linked list, you are given the head of the list.

You need to use the following functions to access the linked list (you **can't** access the `ImmutableListNode` directly):

*   `ImmutableListNode.printValue()`: Print value of the current node.
*   `ImmutableListNode.getNext()`: Return the next node.

The input is only given to initialize the linked list internally. You must solve this problem without modifying the linked list. In other words, you must operate the linked list using only the mentioned APIs.

**Example 1:**

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

**Example 2:**

**Input:** head = \[0,-4,-1,3,-5\]
**Output:** \[-5,3,-1,-4,0\]

**Example 3:**

**Input:** head = \[-2,0,6,4,4,-6\]
**Output:** \[-6,4,4,6,0,-2\]

**Constraints:**

*   The length of the linked list is between `[1, 1000]`.
*   The value of each node in the linked list is between `[-1000, 1000]`.

**Follow up:**

Could you solve this problem in:

*   Constant space complexity?
*   Linear time complexity and less than linear space complexity?

## A solution in Java

```java
public void printLinkedListInReverse(ImmutableListNode head) {
    if (head != null) {
        printLinkedListInReverse(head.getNext());
        head.printValue();
    }
}
```
The algorithm uses a simple recursive approach to solve the problem. Starting from the head of the linked list, it checks if the current node is not null. If the current node is not null, it calls the function recursively with the next Node.

Once the recursion reaches the last Node, the function starts returning and executing the printValue() function for each Node, starting from the last one, which effectively prints the values in reverse order.

This approach uses constant space complexity, but a recursive approach means a linear time complexity. The recursion stack can also overflow for long linked lists. If we want to solve the recursion stack issue, we can use an iterative approach by storing each Node reference in a stack, which improves space complexity but would not be constant anymore (linear space complexity).

## A solution in C++

```cpp
void printLinkedListInReverse(ImmutableListNode* head) {
    if (head != nullptr) {
        printLinkedListInReverse(head->getNext());
        head->printValue();
    }
}
```
The algorithm uses a simple recursive approach to solve the problem. Starting from the head of the linked list, it checks if the current node is not null. If the current node is not null, it calls the function recursively with the next Node.

Once the recursion reaches the last Node, the function starts returning and executing the printValue() function for each Node, starting from the last one, which effectively prints the values in reverse order.

This approach uses constant space complexity, but a recursive approach means a linear time complexity. The recursion stack can also overflow for long linked lists. If we want to solve the recursion stack issue, we can use an iterative approach by storing each Node reference in a stack, which improves space complexity but would not be constant anymore (linear space complexity).

## A solution in Python

```python
def printLinkedListInReverse(head: 'ImmutableListNode') -> None:
    if head is not None:
        printLinkedListInReverse(head.getNext())
        head.printValue()
```
The algorithm uses a simple recursive approach to solve the problem. Starting from the head of the linked list, it checks if the current node is not null. If the current node is not null, it calls the function recursively with the next Node.

Once the recursion reaches the last Node, the function starts returning and executing the printValue() function for each Node, starting from the last one, which effectively prints the values in reverse order.

This approach uses constant space complexity, but a recursive approach means a linear time complexity. The recursion stack can also overflow for long linked lists. If we want to solve the recursion stack issue, we can use an iterative approach by storing each Node reference in a stack, which improves space complexity but would not be constant anymore (linear space complexity).

## A solution in Javascript

```javascript
function printLinkedListInReverse(head) {
    if (head !== null) {
        printLinkedListInReverse(head.getNext());
        head.printValue();
    }
}
```
The algorithm uses a simple recursive approach to solve the problem. Starting from the head of the linked list, it checks if the current node is not null. If the current node is not null, it calls the function recursively with the next Node.

Once the recursion reaches the last Node, the function starts returning and executing the printValue() function for each Node, starting from the last one, which effectively prints the values in reverse order.

This approach uses constant space complexity, but a recursive approach means a linear time complexity. The recursion stack can also overflow for long linked lists. If we want to solve the recursion stack issue, we can use an iterative approach by storing each Node reference in a stack, which improves space complexity but would not be constant anymore (linear space complexity).


# Minimum Time Visiting All Points

- slug: minimum-time-visiting-all-points
- difficulty: Easy

On a 2D plane, there are `n` points with integer coordinates `points[i] = [xi, yi]`. Return _the **minimum time** in seconds to visit all the points in the order given by_ `points`.

You can move according to these rules:

*   In `1` second, you can either:
    *   move vertically by one unit,
    *   move horizontally by one unit, or
    *   move diagonally `sqrt(2)` units (in other words, move one unit vertically then one unit horizontally in `1` second).
*   You have to visit the points in the same order as they appear in the array.
*   You are allowed to pass through points that appear later in the order, but these do not count as visits.

**Example 1:**

**Input:** points = \[\[1,1\],\[3,4\],\[-1,0\]\]
**Output:** 7
**Explanation:** One optimal path is **\[1,1\]** -> \[2,2\] -> \[3,3\] -> **\[3,4\]** \-> \[2,3\] -> \[1,2\] -> \[0,1\] -> **\[-1,0\]**
Time from \[1,1\] to \[3,4\] = 3 seconds
Time from \[3,4\] to \[-1,0\] = 4 seconds
Total time = 7 seconds

**Example 2:**

**Input:** points = \[\[3,2\],\[-2,2\]\]
**Output:** 5

**Constraints:**

*   `points.length == n`
*   `1 <= n <= 100`
*   `points[i].length == 2`
*   `-1000 <= points[i][0], points[i][1] <= 1000`

## A solution in Java

```java
public int minTimeToVisitAllPoints(int[][] points) {
    int time = 0;
    for (int i = 1; i < points.length; i++) {
        int dx = Math.abs(points[i][0] - points[i - 1][0]);
        int dy = Math.abs(points[i][1] - points[i - 1][1]);
        time += Math.max(dx, dy);
    }
    return time;
}
```
We iterate through every point in the given order. At each point, we calculate the horizontal distance `dx` and the vertical distance `dy` between the current point and the previous point. The minimum time to move between these two points is the maximum of `dx` and `dy`. This is because the diagonal movement can shorten both distances simultaneously. We add this value to the total time and continue until all points are visited.

## A solution in C++

```cpp
int minTimeToVisitAllPoints(vector<vector<int>>& points) {
    int time = 0;
    for (int i = 1; i < points.size(); i++) {
        int dx = abs(points[i][0] - points[i - 1][0]);
        int dy = abs(points[i][1] - points[i - 1][1]);
        time += max(dx, dy);
    }
    return time;
}
```
We iterate through every point in the given order. At each point, we calculate the horizontal distance `dx` and the vertical distance `dy` between the current point and the previous point. The minimum time to move between these two points is the maximum of `dx` and `dy`. This is because the diagonal movement can shorten both distances simultaneously. We add this value to the total time and continue until all points are visited.

## A solution in Python

```python
def minTimeToVisitAllPoints(points):
    time = 0
    for i in range(1, len(points)):
        dx = abs(points[i][0] - points[i - 1][0])
        dy = abs(points[i][1] - points[i - 1][1])
        time += max(dx, dy)
    return time
```
We iterate through every point in the given order. At each point, we calculate the horizontal distance `dx` and the vertical distance `dy` between the current point and the previous point. The minimum time to move between these two points is the maximum of `dx` and `dy`. This is because the diagonal movement can shorten both distances simultaneously. We add this value to the total time and continue until all points are visited.

## A solution in Javascript

```javascript
function minTimeToVisitAllPoints(points) {
    let time = 0;
    for (let i = 1; i < points.length; i++) {
        let dx = Math.abs(points[i][0] - points[i - 1][0]);
        let dy = Math.abs(points[i][1] - points[i - 1][1]);
        time += Math.max(dx, dy);
    }
    return time;
}
```
We iterate through every point in the given order. At each point, we calculate the horizontal distance `dx` and the vertical distance `dy` between the current point and the previous point. The minimum time to move between these two points is the maximum of `dx` and `dy`. This is because the diagonal movement can shorten both distances simultaneously. We add this value to the total time and continue until all points are visited.


# Count Servers that Communicate

- slug: count-servers-that-communicate
- difficulty: Medium

You are given a map of a server center, represented as a `m * n` integer matrix `grid`, where 1 means that on that cell there is a server and 0 means that it is no server. Two servers are said to communicate if they are on the same row or on the same column.

Return the number of servers that communicate with any other server.

**Example 1:**

**Input:** grid = \[\[1,0\],\[0,1\]\]
**Output:** 0
**Explanation:** No servers can communicate with others.

**Example 2:**

**Input:** grid = \[\[1,0\],\[1,1\]\]
**Output:** 3
**Explanation:** All three servers can communicate with at least one other server.

**Example 3:**

**Input:** grid = \[\[1,1,0,0\],\[0,0,1,0\],\[0,0,1,0\],\[0,0,0,1\]\]
**Output:** 4
**Explanation:** The two servers in the first row can communicate with each other. The two servers in the third column can communicate with each other. The server at right bottom corner can't communicate with any other server.

**Constraints:**

*   `m == grid.length`
*   `n == grid[i].length`
*   `1 <= m <= 250`
*   `1 <= n <= 250`
*   `grid[i][j] == 0 or 1`

## A solution in Java

```java
public ListNode removeZeroSumSublists(ListNode head) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode current = dummy;

    while (current != null) {
        int sum = 0;
        while (head != null) {
            sum += head.val;
            if (sum == 0) {
                current.next = head.next;
            }
            head = head.next;
        }
        current = current.next;
        if (current != null) {
            head = current.next;
        }
    }

    return dummy.next;
}
```
We create a dummy node as the initial pointer to keep track of the head of the list. We initialize two pointers, current and head, to the dummy node.

We loop through the linked list while current is not a null pointer. Inside the loop, we also loop through the list while head is not a null pointer. We maintain a sum variable to calculate the accumulated sum of the nodes we traverse. If we encounter a node such that the accumulated sum is zero, we update the next pointer of the current node to the next pointer of head.

Outside the inner loop, we assign current to its next pointer and head to the next pointer of current. We repeat this process until we reach the end of the linked list.

Finally, we return the next pointer of the dummy node, which now represents the head of the linked list.

## A solution in C++

```cpp
ListNode* removeZeroSumSublists(ListNode* head) {
    ListNode dummy(0);
    dummy.next = head;
    ListNode* current = &dummy;

    while (current) {
        int sum = 0;
        while (head) {
            sum += head->val;
            if (sum == 0) {
                current->next = head->next;
            }
            head = head->next;
        }
        current = current->next;
        if (current) {
            head = current->next;
        }
    }

    return dummy.next;
}
```
We create a dummy node as the initial pointer to keep track of the head of the list. We initialize two pointers, current and head, to the dummy node.

We loop through the linked list while current is not a null pointer. Inside the loop, we also loop through the list while head is not a null pointer. We maintain a sum variable to calculate the accumulated sum of the nodes we traverse. If we encounter a node such that the accumulated sum is zero, we update the next pointer of the current node to the next pointer of head.

Outside the inner loop, we assign current to its next pointer and head to the next pointer of current. We repeat this process until we reach the end of the linked list.

Finally, we return the next pointer of the dummy node, which now represents the head of the linked list.

## A solution in Python

```python
def remove_zero_sum_sublists(head):
    dummy = ListNode(0)
    dummy.next = head
    current = dummy

    while current:
        sum = 0
        while head:
            sum += head.val
            if sum == 0:
                current.next = head.next
            head = head.next
        current = current.next
        if current:
            head = current.next

    return dummy.next
```
We create a dummy node as the initial pointer to keep track of the head of the list. We initialize two pointers, current and head, to the dummy node.

We loop through the linked list while current is not a null pointer. Inside the loop, we also loop through the list while head is not a null pointer. We maintain a sum variable to calculate the accumulated sum of the nodes we traverse. If we encounter a node such that the accumulated sum is zero, we update the next pointer of the current node to the next pointer of head.

Outside the inner loop, we assign current to its next pointer and head to the next pointer of current. We repeat this process until we reach the end of the linked list.

Finally, we return the next pointer of the dummy node, which now represents the head of the linked list.

## A solution in Javascript

```javascript
function removeZeroSumSublists(head) {
    const dummy = new ListNode(0);
    dummy.next = head;
    let current = dummy;

    while (current) {
        let sum = 0;
        while (head) {
            sum += head.val;
            if (sum === 0) {
                current.next = head.next;
            }
            head = head.next;
        }
        current = current.next;
        if (current) {
            head = current.next;
        }
    }

    return dummy.next;
}
```
We create a dummy node as the initial pointer to keep track of the head of the list. We initialize two pointers, current and head, to the dummy node.

We loop through the linked list while current is not a null pointer. Inside the loop, we also loop through the list while head is not a null pointer. We maintain a sum variable to calculate the accumulated sum of the nodes we traverse. If we encounter a node such that the accumulated sum is zero, we update the next pointer of the current node to the next pointer of head.

Outside the inner loop, we assign current to its next pointer and head to the next pointer of current. We repeat this process until we reach the end of the linked list.

Finally, we return the next pointer of the dummy node, which now represents the head of the linked list.


# Search Suggestions System

- slug: search-suggestions-system
- difficulty: Medium

You are given an array of strings `products` and a string `searchWord`.

Design a system that suggests at most three product names from `products` after each character of `searchWord` is typed. Suggested products should have common prefix with `searchWord`. If there are more than three products with a common prefix return the three lexicographically minimums products.

Return _a list of lists of the suggested products after each character of_ `searchWord` _is typed_.

**Example 1:**

**Input:** products = \[ "mobile ", "mouse ", "moneypot ", "monitor ", "mousepad "\], searchWord =  "mouse "
**Output:** \[\[ "mobile ", "moneypot ", "monitor "\],\[ "mobile ", "moneypot ", "monitor "\],\[ "mouse ", "mousepad "\],\[ "mouse ", "mousepad "\],\[ "mouse ", "mousepad "\]\]
**Explanation:** products sorted lexicographically = \[ "mobile ", "moneypot ", "monitor ", "mouse ", "mousepad "\].
After typing m and mo all products match and we show user \[ "mobile ", "moneypot ", "monitor "\].
After typing mou, mous and mouse the system suggests \[ "mouse ", "mousepad "\].

**Example 2:**

**Input:** products = \[ "havana "\], searchWord =  "havana "
**Output:** \[\[ "havana "\],\[ "havana "\],\[ "havana "\],\[ "havana "\],\[ "havana "\],\[ "havana "\]\]
**Explanation:** The only word  "havana " will be always suggested while typing the search word.

**Constraints:**

*   `1 <= products.length <= 1000`
*   `1 <= products[i].length <= 3000`
*   `1 <= sum(products[i].length) <= 2 * 104`
*   All the strings of `products` are **unique**.
*   `products[i]` consists of lowercase English letters.
*   `1 <= searchWord.length <= 1000`
*   `searchWord` consists of lowercase English letters.

## A solution in Java

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

public List<List<String>> suggestedProducts(String[] products, String searchWord) {
    List<List<String>> result = new ArrayList<>();
    Arrays.sort(products);

    for (int i = 0; i < searchWord.length(); ++i) {
        List<String> suggestions = new ArrayList<>();
        for (String product : products) {
            if (product.length() > i && product.charAt(i) == searchWord.charAt(i)) {
                suggestions.add(product);
                if (suggestions.size() == 3) break;
            }
        }
        result.add(suggestions);
    }

    return result;
}
```
The given problem can be solved with a simple sorting and iteration approach. The algorithm works as follows:

1. Sort the `products` list lexicographically.
2. Iterate through each character in the `searchWord`.
3. For each character, initialize an empty list `suggestions` to store the suggested products.
4. Iterate through each product in the `products` list.
5. If the product has the same character at the current position as the `searchWord`, add the product to the `suggestions` list.
6. Break the loop if the `suggestions` list has 3 elements, as we need at most 3 product suggestions at a time.
7. After iterating through all products, add the `suggestions` list to the `result` list.
8. Repeat steps 3-7 for each character in the `searchWord`.
9. Return the `result` list containing lists of suggested products after each character of `searchWord`.

This algorithm solves the problem with a simple traversal approach and doesn't require any complex data structures or techniques.

## A solution in C++

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

std::vector<std::vector<std::string>> suggestedProducts(std::vector<std::string>& products, std::string searchWord) {
    std::vector<std::vector<std::string>> result;
    std::sort(products.begin(), products.end());

    for (int i = 0; i < searchWord.size(); ++i) {
        std::vector<std::string> suggestions;
        for (const auto& product : products) {
            if (product.size() > i && product[i] == searchWord[i]) {
                suggestions.push_back(product);
                if (suggestions.size() == 3) break;
            }
        }
        result.push_back(suggestions);
    }

    return result;
}
```
The given problem can be solved with a simple sorting and iteration approach. The algorithm works as follows:

1. Sort the `products` list lexicographically.
2. Iterate through each character in the `searchWord`.
3. For each character, initialize an empty list `suggestions` to store the suggested products.
4. Iterate through each product in the `products` list.
5. If the product has the same character at the current position as the `searchWord`, add the product to the `suggestions` list.
6. Break the loop if the `suggestions` list has 3 elements, as we need at most 3 product suggestions at a time.
7. After iterating through all products, add the `suggestions` list to the `result` list.
8. Repeat steps 3-7 for each character in the `searchWord`.
9. Return the `result` list containing lists of suggested products after each character of `searchWord`.

This algorithm solves the problem with a simple traversal approach and doesn't require any complex data structures or techniques.

## A solution in Python

```python
def suggestedProducts(products, searchWord):
    result = []
    products.sort()

    for i in range(len(searchWord)):
        suggestions = []
        for product in products:
            if len(product) > i and product[i] == searchWord[i]:
                suggestions.append(product)
                if len(suggestions) == 3:
                    break
        result.append(suggestions)

    return result
```
The given problem can be solved with a simple sorting and iteration approach. The algorithm works as follows:

1. Sort the `products` list lexicographically.
2. Iterate through each character in the `searchWord`.
3. For each character, initialize an empty list `suggestions` to store the suggested products.
4. Iterate through each product in the `products` list.
5. If the product has the same character at the current position as the `searchWord`, add the product to the `suggestions` list.
6. Break the loop if the `suggestions` list has 3 elements, as we need at most 3 product suggestions at a time.
7. After iterating through all products, add the `suggestions` list to the `result` list.
8. Repeat steps 3-7 for each character in the `searchWord`.
9. Return the `result` list containing lists of suggested products after each character of `searchWord`.

This algorithm solves the problem with a simple traversal approach and doesn't require any complex data structures or techniques.

## A solution in Javascript

```javascript
function suggestedProducts(products, searchWord) {
    let result = [];
    products.sort();

    for (let i = 0; i < searchWord.length; ++i) {
        let suggestions = [];
        for (let product of products) {
            if (product.length > i && product[i] === searchWord[i]) {
                suggestions.push(product);
                if (suggestions.length === 3) break;
            }
        }
        result.push(suggestions);
    }

    return result;
}
```
The given problem can be solved with a simple sorting and iteration approach. The algorithm works as follows:

1. Sort the `products` list lexicographically.
2. Iterate through each character in the `searchWord`.
3. For each character, initialize an empty list `suggestions` to store the suggested products.
4. Iterate through each product in the `products` list.
5. If the product has the same character at the current position as the `searchWord`, add the product to the `suggestions` list.
6. Break the loop if the `suggestions` list has 3 elements, as we need at most 3 product suggestions at a time.
7. After iterating through all products, add the `suggestions` list to the `result` list.
8. Repeat steps 3-7 for each character in the `searchWord`.
9. Return the `result` list containing lists of suggested products after each character of `searchWord`.

This algorithm solves the problem with a simple traversal approach and doesn't require any complex data structures or techniques.