# Random Pick with Blacklist

- slug: random-pick-with-blacklist
- difficulty: Hard

You are given an integer `n` and an array of **unique** integers `blacklist`. Design an algorithm to pick a random integer in the range `[0, n - 1]` that is **not** in `blacklist`. Any integer that is in the mentioned range and not in `blacklist` should be **equally likely** to be returned.

Optimize your algorithm such that it minimizes the number of calls to the **built-in** random function of your language.

Implement the `Solution` class:

*   `Solution(int n, int[] blacklist)` Initializes the object with the integer `n` and the blacklisted integers `blacklist`.
*   `int pick()` Returns a random integer in the range `[0, n - 1]` and not in `blacklist`.

**Example 1:**

**Input**
\[ "Solution ",  "pick ",  "pick ",  "pick ",  "pick ",  "pick ",  "pick ",  "pick "\]
\[\[7, \[2, 3, 5\]\], \[\], \[\], \[\], \[\], \[\], \[\], \[\]\]
**Output**
\[null, 0, 4, 1, 6, 1, 0, 4\]

**Explanation**
Solution solution = new Solution(7, \[2, 3, 5\]);
solution.pick(); // return 0, any integer from \[0,1,4,6\] should be ok. Note that for every call of pick,
                 // 0, 1, 4, and 6 must be equally likely to be returned (i.e., with probability 1/4).
solution.pick(); // return 4
solution.pick(); // return 1
solution.pick(); // return 6
solution.pick(); // return 1
solution.pick(); // return 0
solution.pick(); // return 4

**Constraints:**

*   `1 <= n <= 109`
*   `0 <= blacklist.length <= min(105, n - 1)`
*   `0 <= blacklist[i] < n`
*   All the values of `blacklist` are **unique**.
*   At most `2 * 104` calls will be made to `pick`.

## A solution in Java

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

class Solution {
    private HashMap<Integer, Integer> mapping;
    private int last;
    private Random random;

    public Solution(int n, int[] blacklist) {
        Arrays.sort(blacklist);
        mapping = new HashMap<>();
        int idx = 0;
        for (int i = 0; i < blacklist.length; ++i) {
            int black = blacklist[i];
            while (idx < black) {
                mapping.put(idx++, --n);
            }
            idx++;
            n--;
        }
        last = n;
        random = new Random();
    }

    public int pick() {
        int num = random.nextInt(last);
        return mapping.getOrDefault(num, num);
    }
}
```
We create a mapping from the non-blacklisted range `[0, n - blacklist.size())` to the full available range `[0, n)`. For each non-blacklisted number `num`, the mapping contains the non-blacklisted number that corresponds to its position `num - blacklist[i]` in the full available range. We initialize the mapping by iterating over the sorted `blacklist`, and we pick a random integer in the non-blacklisted range and use the mapping to get the corresponding available number. To minimize the number of calls to the random function, we only call it once per `pick()` call. This ensures that any integer in the non-blacklisted range is equally likely to be returned.

## A solution in C++

```cpp
#include <unordered_map>
#include <vector>
#include <algorithm>
#include <random>

class Solution {
public:
    Solution(int n, std::vector<int>& blacklist) {
        std::sort(blacklist.begin(), blacklist.end());
        auto it = blacklist.begin();
        int idx = 0;
        for (int i = 0; i < blacklist.size(); ++i) {
            int black = *it++;
            while (idx < black) {
                mapping[idx++] = n - 1;
                --n;
            }
            ++idx;
            --n;
        }
        last = n;
    }

    int pick() {
        int num = rand() % last;
        auto res = mapping.find(num);
        return res == mapping.end() ? num : res->second;
    }

private:
    std::unordered_map<int, int> mapping;
    int last;
};
```
We create a mapping from the non-blacklisted range `[0, n - blacklist.size())` to the full available range `[0, n)`. For each non-blacklisted number `num`, the mapping contains the non-blacklisted number that corresponds to its position `num - blacklist[i]` in the full available range. We initialize the mapping by iterating over the sorted `blacklist`, and we pick a random integer in the non-blacklisted range and use the mapping to get the corresponding available number. To minimize the number of calls to the random function, we only call it once per `pick()` call. This ensures that any integer in the non-blacklisted range is equally likely to be returned.

## A solution in Python

```python
import random

class Solution:
    def __init__(self, n: int, blacklist: List[int]):
        blacklist.sort()
        self.mapping = dict()
        idx = 0
        for black in blacklist:
            while idx < black:
                self.mapping[idx] = n - 1
                idx += 1
                n -= 1
            idx += 1
            n -= 1
        self.last = n

    def pick(self) -> int:
        num = random.randrange(self.last)
        return self.mapping.get(num, num)
```
We create a mapping from the non-blacklisted range `[0, n - blacklist.size())` to the full available range `[0, n)`. For each non-blacklisted number `num`, the mapping contains the non-blacklisted number that corresponds to its position `num - blacklist[i]` in the full available range. We initialize the mapping by iterating over the sorted `blacklist`, and we pick a random integer in the non-blacklisted range and use the mapping to get the corresponding available number. To minimize the number of calls to the random function, we only call it once per `pick()` call. This ensures that any integer in the non-blacklisted range is equally likely to be returned.

## A solution in Javascript

```javascript
class Solution {
    constructor(n, blacklist) {
        blacklist.sort((a, b) => a - b);
        this.mapping = new Map();
        let idx = 0;
        for (let i = 0; i < blacklist.length; ++i) {
            let black = blacklist[i];
            while (idx < black) {
                this.mapping.set(idx++, n - 1);
                n--;
            }
            idx++;
            n--;
        }
        this.last = n;
    }

    pick() {
        const num = Math.floor(Math.random() * this.last);
        return this.mapping.has(num) ? this.mapping.get(num) : num;
    }
}
```
We create a mapping from the non-blacklisted range `[0, n - blacklist.size())` to the full available range `[0, n)`. For each non-blacklisted number `num`, the mapping contains the non-blacklisted number that corresponds to its position `num - blacklist[i]` in the full available range. We initialize the mapping by iterating over the sorted `blacklist`, and we pick a random integer in the non-blacklisted range and use the mapping to get the corresponding available number. To minimize the number of calls to the random function, we only call it once per `pick()` call. This ensures that any integer in the non-blacklisted range is equally likely to be returned.


# Number of Distinct Islands II

- slug: number-of-distinct-islands-ii
- difficulty: Hard

You are given an `m x n` binary matrix `grid`. An island is a group of `1`'s (representing land) connected **4-directionally** (horizontal or vertical.) You may assume all four edges of the grid are surrounded by water.

An island is considered to be the same as another if they have the same shape, or have the same shape after **rotation** (90, 180, or 270 degrees only) or **reflection** (left/right direction or up/down direction).

Return _the number of **distinct** islands_.

**Example 1:**

**Input:** grid = \[\[1,1,0,0,0\],\[1,0,0,0,0\],\[0,0,0,0,1\],\[0,0,0,1,1\]\]
**Output:** 1
**Explanation:** The two islands are considered the same because if we make a 180 degrees clockwise rotation on the first island, then two islands will have the same shapes.

**Example 2:**

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

**Constraints:**

*   `m == grid.length`
*   `n == grid[i].length`
*   `1 <= m, n <= 50`
*   `grid[i][j]` is either `0` or `1`.

## A solution in Java

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

class Solution {
    private void dfs(int r, int c, int r0, int c0, int[][] grid, ArrayList<int[]> island){
        if (r >= 0 && c >= 0 && r < grid.length && c < grid[0].length && grid[r][c] == 1) {
            grid[r][c] = 0;
            island.add(new int[]{r - r0, c - c0});
            dfs(r + 1, c, r0, c0, grid, island);
            dfs(r - 1, c, r0, c0, grid, island);
            dfs(r, c + 1, r0, c0, grid, island);
            dfs(r, c - 1, r0, c0, grid, island);
        }
    }

    private String normalize(ArrayList<int[]> island) {
        ArrayList<String> ret = new ArrayList<>();
        for (int[] p : island) {
            int x = p[0];
            int y = p[1];
            ret.add(x + "," + y);
            ret.add(x + "," + -y);
            ret.add(-x + "," + y);
            ret.add(-x + "," + -y);
            ret.add(y + "," + x);
            ret.add(y + "," + -x);
            ret.add(-y + "," + x);
            ret.add(-y + "," + -x);
        }
        ret.sort(String::compareTo);
        return String.join(" ", ret);
    }

    public int numDistinctIslands(int[][] grid) {
        Set<String> distinctIslands = new HashSet<>();
        for (int r = 0; r < grid.length; ++r) {
            for (int c = 0; c < grid[r].length; ++c) {
                if (grid[r][c] == 1) {
                    ArrayList<int[]> island = new ArrayList<>();
                    dfs(r, c, r, c, grid, island);
                    distinctIslands.add(normalize(island));
                }
            }
        }
        return distinctIslands.size();
    }
}
```
The algorithm uses DFS to traverse each island in the grid. For each island, it calculates its normalized form by considering all possible rotations and reflections. This normalized form is the "key" for this island. Then, the algorithm uses a set to count the number of distinct islands.

1. For each cell in the grid, if it's 1, run DFS and find the positions of the island.
2. Normalize the positions by comparing them to all possible rotations and reflections, and choosing the lexicographically SMALLEST of these forms. By this way, all the forms considered the same will have the same "key". This "key" is a sorted list of the positions.
3. Add the normalized positions to the set. Since sets only store unique items, we can count the number of distinct islands by counting the size of the set after iterating through the whole grid.

## A solution in C++

```cpp
#include <unordered_set>
#include <vector>

class Solution {
private:
    void dfs(int r, int c, int r0, int c0, std::vector<std::vector<int>>& grid, std::vector<std::pair<int, int>>& island){
        if (r >= 0 && c >= 0 && r < grid.size() && c < grid[r].size() && grid[r][c] == 1) {
            grid[r][c] = 0;
            island.push_back({r - r0, c - c0});
            dfs(r + 1, c, r0, c0, grid, island);
            dfs(r - 1, c, r0, c0, grid, island);
            dfs(r, c + 1, r0, c0, grid, island);
            dfs(r, c - 1, r0, c0, grid, island);
        }
    }

    std::vector<std::pair<int, int>> normalize(std::vector<std::pair<int, int>>& island) {
        std::vector<std::vector<std::pair<int, int>>> ret(8);
        for (const auto& p : island) {
            int x = p.first;
            int y = p.second;
            ret[0].push_back({x, y});
            ret[1].push_back({x, -y});
            ret[2].push_back({-x, y});
            ret[3].push_back({-x, -y});
            ret[4].push_back({y, x});
            ret[5].push_back({y, -x});
            ret[6].push_back({-y, x});
            ret[7].push_back({-y, -x});
        }
        for (auto& list : ret) {
            std::sort(list.begin(), list.end());
        }
        std::sort(ret.begin(), ret.end());
        return ret[0];
    }

public:
    int numDistinctIslands(std::vector<std::vector<int>>& grid) {
        std::unordered_set<std::string> distinctIslands;
        for (int r = 0; r < grid.size(); ++r) {
            for (int c = 0; c < grid[r].size(); ++c) {
                if (grid[r][c] == 1) {
                    std::vector<std::pair<int, int>> island;
                    dfs(r, c, r, c, grid, island);
                    distinctIslands.insert(normalize(island));
                }
            }
        }
        return distinctIslands.size();
    }
};
```
The algorithm uses DFS to traverse each island in the grid. For each island, it calculates its normalized form by considering all possible rotations and reflections. This normalized form is the "key" for this island. Then, the algorithm uses a set to count the number of distinct islands.

1. For each cell in the grid, if it's 1, run DFS and find the positions of the island.
2. Normalize the positions by comparing them to all possible rotations and reflections, and choosing the lexicographically SMALLEST of these forms. By this way, all the forms considered the same will have the same "key". This "key" is a sorted list of the positions.
3. Add the normalized positions to the set. Since sets only store unique items, we can count the number of distinct islands by counting the size of the set after iterating through the whole grid.

## A solution in Python

```python
class Solution:
    def numDistinctIslands(self, grid: List[List[int]]) -> int:
        def dfs(r, c, r0, c0):
            if 0 <= r < len(grid) and 0 <= c < len(grid[0]) and grid[r][c]:
                grid[r][c] = 0
                island.append((r - r0, c - c0))
                dfs(r + 1, c, r0, c0)
                dfs(r - 1, c, r0, c0)
                dfs(r, c + 1, r0, c0)
                dfs(r, c - 1, r0, c0)

        def normalize(island):
            ret = []
            for p in island:
                x, y = p
                ret += [(x, y), (x, -y), (-x, y), (-x, -y), (y, x), (y, -x), (-y, x), (-y, -x)]
            ret.sort()
            return tuple(ret)

        distinctIslands = set()
        for r in range(len(grid)):
            for c in range(len(grid[0])):
                if grid[r][c]:
                    island = []
                    dfs(r, c, r, c)
                    distinctIslands.add(normalize(island))
        return len(distinctIslands)
```
The algorithm uses DFS to traverse each island in the grid. For each island, it calculates its normalized form by considering all possible rotations and reflections. This normalized form is the "key" for this island. Then, the algorithm uses a set to count the number of distinct islands.

1. For each cell in the grid, if it's 1, run DFS and find the positions of the island.
2. Normalize the positions by comparing them to all possible rotations and reflections, and choosing the lexicographically SMALLEST of these forms. By this way, all the forms considered the same will have the same "key". This "key" is a sorted list of the positions.
3. Add the normalized positions to the set. Since sets only store unique items, we can count the number of distinct islands by counting the size of the set after iterating through the whole grid.

## A solution in Javascript

```javascript
class Solution {
    numDistinctIslands(grid) {
        let distinctIslands = new Set();

        const dfs = (r, c, r0, c0) => {
            if (r >= 0 && c >= 0 && r < grid.length && c < grid[0].length && grid[r][c] === 1) {
                grid[r][c] = 0;
                island.push([r - r0, c - c0]);
                dfs(r + 1, c, r0, c0);
                dfs(r - 1, c, r0, c0);
                dfs(r, c + 1, r0, c0);
                dfs(r, c - 1, r0, c0);
            }
        };

        const normalize = (island) => {
            let ret = [];
            island.forEach(p => {
                let [x, y] = p;
                ret.push(...[[x, y], [x, -y], [-x, y], [-x, -y], [y, x], [y, -x], [-y, x], [-y, -x]]);
            });
            ret.sort((a, b) => a[0] - b[0] || a[1] - b[1]);
            return JSON.stringify(ret);
        };

        for (let r = 0; r < grid.length; ++r) {
            for (let c = 0; c < grid[r].length; ++c) {
                if (grid[r][c] === 1) {
                    let island = [];
                    dfs(r, c, r, c);
                    distinctIslands.add(normalize(island));
                }
            }
        }
        return distinctIslands.size;
    }
}
```
The algorithm uses DFS to traverse each island in the grid. For each island, it calculates its normalized form by considering all possible rotations and reflections. This normalized form is the "key" for this island. Then, the algorithm uses a set to count the number of distinct islands.

1. For each cell in the grid, if it's 1, run DFS and find the positions of the island.
2. Normalize the positions by comparing them to all possible rotations and reflections, and choosing the lexicographically SMALLEST of these forms. By this way, all the forms considered the same will have the same "key". This "key" is a sorted list of the positions.
3. Add the normalized positions to the set. Since sets only store unique items, we can count the number of distinct islands by counting the size of the set after iterating through the whole grid.


# Minimum ASCII Delete Sum for Two Strings

- slug: minimum-ascii-delete-sum-for-two-strings
- difficulty: Medium

Given two strings `s1` and `s2`, return _the lowest **ASCII** sum of deleted characters to make two strings equal_.

**Example 1:**

**Input:** s1 =  "sea ", s2 =  "eat "
**Output:** 231
**Explanation:** Deleting  "s " from  "sea " adds the ASCII value of  "s " (115) to the sum.
Deleting  "t " from  "eat " adds 116 to the sum.
At the end, both strings are equal, and 115 + 116 = 231 is the minimum sum possible to achieve this.

**Example 2:**

**Input:** s1 =  "delete ", s2 =  "leet "
**Output:** 403
**Explanation:** Deleting  "dee " from  "delete " to turn the string into  "let ",
adds 100\[d\] + 101\[e\] + 101\[e\] to the sum.
Deleting  "e " from  "leet " adds 101\[e\] to the sum.
At the end, both strings are equal to  "let ", and the answer is 100+101+101+101 = 403.
If instead we turned both strings into  "lee " or  "eet ", we would get answers of 433 or 417, which are higher.

**Constraints:**

*   `1 <= s1.length, s2.length <= 1000`
*   `s1` and `s2` consist of lowercase English letters.

## A solution in Java

```java
public int minimumDeleteSum(String s1, String s2) {
    int[][] dp = new int[s1.length() + 1][s2.length() + 1];
    for (int i = 1; i <= s1.length(); i++) {
        dp[i][0] = dp[i - 1][0] + s1.charAt(i - 1);
    }
    for (int j = 1; j <= s2.length(); j++) {
        dp[0][j] = dp[0][j - 1] + s2.charAt(j - 1);
    }
    for (int i = 1; i <= s1.length(); i++) {
        for (int j = 1; j <= s2.length(); j++) {
            if (s1.charAt(i - 1) == s2.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = Math.min(dp[i - 1][j] + s1.charAt(i - 1), dp[i][j - 1] + s2.charAt(j - 1));
            }
        }
    }
    return dp[s1.length()][s2.length()];
}
```
For this problem, we use dynamic programming. First, we create a 2D array `dp` to store the intermediate results. Each cell dp[i][j] in the `dp` array represents the lowest ASCII sum of deleted characters to make the first i characters of s1 and the first j characters of s2 equal.

We initialize the first column of the `dp` array to the ASCII sum of s1 characters and the first row to the ASCII sum of s2 characters. Then, we loop through the entire `dp` array, updating the values lexicographically. If the characters at the respective indexes of s1 and s2 are the same, we just copy the value of dp[i-1][j-1] to dp[i][j]. If they are different, we calculate the minimum between deleting the character from s1 (dp[i-1][j] + ASCII value of the character) and deleting the character from s2 (dp[i][j-1] + ASCII value of the character).

Finally, we return the value at the bottom-right corner of the `dp` array, which represents the lowest ASCII sum needed to make s1 and s2 equal.

## A solution in C++

```cpp
int minimumDeleteSum(std::string s1, std::string s2) {
    int dp[1001][1001] = {0};
    for (int i = 1; i <= s1.size(); i++) {
        dp[i][0] = dp[i - 1][0] + s1[i - 1];
    }
    for (int j = 1; j <= s2.size(); j++) {
        dp[0][j] = dp[0][j - 1] + s2[j - 1];
    }
    for (int i = 1; i <= s1.size(); i++) {
        for (int j = 1; j <= s2.size(); j++) {
            if (s1[i - 1] == s2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = std::min(dp[i - 1][j] + s1[i - 1], dp[i][j - 1] + s2[j - 1]);
            }
        }
    }
    return dp[s1.size()][s2.size()];
}
```
For this problem, we use dynamic programming. First, we create a 2D array `dp` to store the intermediate results. Each cell dp[i][j] in the `dp` array represents the lowest ASCII sum of deleted characters to make the first i characters of s1 and the first j characters of s2 equal.

We initialize the first column of the `dp` array to the ASCII sum of s1 characters and the first row to the ASCII sum of s2 characters. Then, we loop through the entire `dp` array, updating the values lexicographically. If the characters at the respective indexes of s1 and s2 are the same, we just copy the value of dp[i-1][j-1] to dp[i][j]. If they are different, we calculate the minimum between deleting the character from s1 (dp[i-1][j] + ASCII value of the character) and deleting the character from s2 (dp[i][j-1] + ASCII value of the character).

Finally, we return the value at the bottom-right corner of the `dp` array, which represents the lowest ASCII sum needed to make s1 and s2 equal.

## A solution in Python

```python
def minimumDeleteSum(s1: str, s2: str) -> int:
    dp = [[0] * (len(s2) + 1) for _ in range(len(s1) + 1)]
    for i in range(1, len(s1) + 1):
        dp[i][0] = dp[i - 1][0] + ord(s1[i - 1])
    for j in range(1, len(s2) + 1):
        dp[0][j] = dp[0][j - 1] + ord(s2[j - 1])
    for i in range(1, len(s1) + 1):
        for j in range(1, len(s2) + 1):
            if s1[i - 1] == s2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1]
            else:
                dp[i][j] = min(dp[i - 1][j] + ord(s1[i - 1]), dp[i][j - 1] + ord(s2[j - 1]))
    return dp[len(s1)][len(s2)]
```
For this problem, we use dynamic programming. First, we create a 2D array `dp` to store the intermediate results. Each cell dp[i][j] in the `dp` array represents the lowest ASCII sum of deleted characters to make the first i characters of s1 and the first j characters of s2 equal.

We initialize the first column of the `dp` array to the ASCII sum of s1 characters and the first row to the ASCII sum of s2 characters. Then, we loop through the entire `dp` array, updating the values lexicographically. If the characters at the respective indexes of s1 and s2 are the same, we just copy the value of dp[i-1][j-1] to dp[i][j]. If they are different, we calculate the minimum between deleting the character from s1 (dp[i-1][j] + ASCII value of the character) and deleting the character from s2 (dp[i][j-1] + ASCII value of the character).

Finally, we return the value at the bottom-right corner of the `dp` array, which represents the lowest ASCII sum needed to make s1 and s2 equal.

## A solution in Javascript

```javascript
function minimumDeleteSum(s1, s2) {
    const dp = Array.from({ length: s1.length + 1 }, () => Array(s2.length + 1).fill(0));
    for (let i = 1; i <= s1.length; i++) {
        dp[i][0] = dp[i - 1][0] + s1.charCodeAt(i - 1);
    }
    for (let j = 1; j <= s2.length; j++) {
        dp[0][j] = dp[0][j - 1] + s2.charCodeAt(j - 1);
    }
    for (let i = 1; i <= s1.length; i++) {
        for (let j = 1; j <= s2.length; j++) {
            if (s1.charAt(i - 1) === s2.charAt(j - 1)) {
                dp[i][j] = dp[i - 1][j - 1];
            } else {
                dp[i][j] = Math.min(dp[i - 1][j] + s1.charCodeAt(i - 1), dp[i][j - 1] + s2.charCodeAt(j - 1));
            }
        }
    }
    return dp[s1.length][s2.length];
}
```
For this problem, we use dynamic programming. First, we create a 2D array `dp` to store the intermediate results. Each cell dp[i][j] in the `dp` array represents the lowest ASCII sum of deleted characters to make the first i characters of s1 and the first j characters of s2 equal.

We initialize the first column of the `dp` array to the ASCII sum of s1 characters and the first row to the ASCII sum of s2 characters. Then, we loop through the entire `dp` array, updating the values lexicographically. If the characters at the respective indexes of s1 and s2 are the same, we just copy the value of dp[i-1][j-1] to dp[i][j]. If they are different, we calculate the minimum between deleting the character from s1 (dp[i-1][j] + ASCII value of the character) and deleting the character from s2 (dp[i][j-1] + ASCII value of the character).

Finally, we return the value at the bottom-right corner of the `dp` array, which represents the lowest ASCII sum needed to make s1 and s2 equal.


# Subarray Product Less Than K

- slug: subarray-product-less-than-k
- difficulty: Medium

Given an array of integers `nums` and an integer `k`, return _the number of contiguous subarrays where the product of all the elements in the subarray is strictly less than_ `k`.

**Example 1:**

**Input:** nums = \[10,5,2,6\], k = 100
**Output:** 8
**Explanation:** The 8 subarrays that have product less than 100 are:
\[10\], \[5\], \[2\], \[6\], \[10, 5\], \[5, 2\], \[2, 6\], \[5, 2, 6\]
Note that \[10, 5, 2\] is not included as the product of 100 is not strictly less than k.

**Example 2:**

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

**Constraints:**

*   `1 <= nums.length <= 3 * 104`
*   `1 <= nums[i] <= 1000`
*   `0 <= k <= 106`

## A solution in Java

```java
public int numSubarrayProductLessThanK(int[] nums, int k) {
    if (k <= 1) return 0;
    int prod = 1, count = 0, left = 0;
    for (int right = 0; right < nums.length; right++) {
        prod *= nums[right];
        while (prod >= k) prod /= nums[left++];
        count += right - left + 1;
    }
    return count;
}
```
The algorithm uses a sliding window approach to find the contiguous subarrays with the product less than k. It initializes a product variable to 1, and count variable to 0.  We also have left and right pointers for our sliding window.

For each number in the array, we multiply the product by the current number. Inside a loop, we check if the product is greater than or equal to k; if it is, we divide the product by the number at the left pointer and move the left pointer to the right.

After adjusting the product and the left pointer, we can calculate the length of the current window. We increment the count by the length of the window.

At the end, we return the total count of subarrays with product less than k.

## A solution in C++

```cpp
int numSubarrayProductLessThanK(vector<int>& nums, int k) {
    if (k <= 1) return 0;
    int prod = 1, count = 0, left = 0;
    for (int right = 0; right < nums.size(); right++) {
        prod *= nums[right];
        while (prod >= k) prod /= nums[left++];
        count += right - left + 1;
    }
    return count;
}
```
The algorithm uses a sliding window approach to find the contiguous subarrays with the product less than k. It initializes a product variable to 1, and count variable to 0.  We also have left and right pointers for our sliding window.

For each number in the array, we multiply the product by the current number. Inside a loop, we check if the product is greater than or equal to k; if it is, we divide the product by the number at the left pointer and move the left pointer to the right.

After adjusting the product and the left pointer, we can calculate the length of the current window. We increment the count by the length of the window.

At the end, we return the total count of subarrays with product less than k.

## A solution in Python

```python
def numSubarrayProductLessThanK(nums, k):
    if k <= 1:
        return 0
    prod = 1
    count = 0
    left = 0
    for right in range(len(nums)):
        prod *= nums[right]
        while prod >= k:
            prod /= nums[left]
            left += 1
        count += right - left + 1
    return count
```
The algorithm uses a sliding window approach to find the contiguous subarrays with the product less than k. It initializes a product variable to 1, and count variable to 0.  We also have left and right pointers for our sliding window.

For each number in the array, we multiply the product by the current number. Inside a loop, we check if the product is greater than or equal to k; if it is, we divide the product by the number at the left pointer and move the left pointer to the right.

After adjusting the product and the left pointer, we can calculate the length of the current window. We increment the count by the length of the window.

At the end, we return the total count of subarrays with product less than k.

## A solution in Javascript

```javascript
function numSubarrayProductLessThanK(nums, k) {
    if (k <= 1) return 0;
    let prod = 1, count = 0, left = 0;
    for (let right = 0; right < nums.length; right++) {
        prod *= nums[right];
        while (prod >= k) prod /= nums[left++];
        count += right - left + 1;
    }
    return count;
}
```
The algorithm uses a sliding window approach to find the contiguous subarrays with the product less than k. It initializes a product variable to 1, and count variable to 0.  We also have left and right pointers for our sliding window.

For each number in the array, we multiply the product by the current number. Inside a loop, we check if the product is greater than or equal to k; if it is, we divide the product by the number at the left pointer and move the left pointer to the right.

After adjusting the product and the left pointer, we can calculate the length of the current window. We increment the count by the length of the window.

At the end, we return the total count of subarrays with product less than k.


# Best Time to Buy and Sell Stock with Transaction Fee

- slug: best-time-to-buy-and-sell-stock-with-transaction-fee
- difficulty: Medium

You are given an array `prices` where `prices[i]` is the price of a given stock on the `ith` day, and an integer `fee` representing a transaction fee.

Find the maximum profit you can achieve. You may complete as many transactions as you like, but you need to pay the transaction fee for each transaction.

**Note:** You may not engage in multiple transactions simultaneously (i.e., you must sell the stock before you buy again).

**Example 1:**

**Input:** prices = \[1,3,2,8,4,9\], fee = 2
**Output:** 8
**Explanation:** The maximum profit can be achieved by:
- Buying at prices\[0\] = 1
- Selling at prices\[3\] = 8
- Buying at prices\[4\] = 4
- Selling at prices\[5\] = 9
The total profit is ((8 - 1) - 2) + ((9 - 4) - 2) = 8.

**Example 2:**

**Input:** prices = \[1,3,7,5,10,3\], fee = 3
**Output:** 6

**Constraints:**

*   `1 <= prices.length <= 5 * 104`
*   `1 <= prices[i] < 5 * 104`
*   `0 <= fee < 5 * 104`

## A solution in Java

```java
public int maxProfit(int[] prices, int fee) {
    int cash = 0, hold = -prices[0];
    for (int price : prices) {
        int temp = cash;
        cash = Math.max(cash, hold + price - fee);
        hold = Math.max(hold, temp - price);
    }
    return cash;
}
```
The algorithm utilizes dynamic programming to solve the problem. We maintain two variables, `cash` and `hold`. `cash` represents the maximum profit we can achieve when we hold no stock (sell or not buy it), whereas `hold` represents the maximum profit we can achieve when we hold the stock (buy or not sell it).

1. Initialize `cash` to 0 and `hold` to `-prices[0]`. (Initially, we assume that we buy the stock on the first day)
2. Iterate through the `prices` array.
3. In each iteration, we update `cash` as maximum of the current value of `cash` and `hold + price - fee`. This means that we either sell the stock at the current price (subtracting the transaction fee) or don't take any action.
4. Similarly, update `hold` as maximum of current value of `hold` and `cash - price`. This means that we either buy the stock at the current price or don't take any action.
5. After iterating through the entire `prices` array, return the final value of `cash` as the maximum profit.

## A solution in C++

```cpp
int maxProfit(vector<int>& prices, int fee) {
    int cash = 0, hold = -prices[0];
    for (int price : prices) {
        int temp = cash;
        cash = max(cash, hold + price - fee);
        hold = max(hold, temp - price);
    }
    return cash;
}
```
The algorithm utilizes dynamic programming to solve the problem. We maintain two variables, `cash` and `hold`. `cash` represents the maximum profit we can achieve when we hold no stock (sell or not buy it), whereas `hold` represents the maximum profit we can achieve when we hold the stock (buy or not sell it).

1. Initialize `cash` to 0 and `hold` to `-prices[0]`. (Initially, we assume that we buy the stock on the first day)
2. Iterate through the `prices` array.
3. In each iteration, we update `cash` as maximum of the current value of `cash` and `hold + price - fee`. This means that we either sell the stock at the current price (subtracting the transaction fee) or don't take any action.
4. Similarly, update `hold` as maximum of current value of `hold` and `cash - price`. This means that we either buy the stock at the current price or don't take any action.
5. After iterating through the entire `prices` array, return the final value of `cash` as the maximum profit.

## A solution in Python

```python
def maxProfit(prices, fee):
    cash, hold = 0, -prices[0]
    for price in prices:
        temp = cash
        cash = max(cash, hold + price - fee)
        hold = max(hold, temp - price)
    return cash
```
The algorithm utilizes dynamic programming to solve the problem. We maintain two variables, `cash` and `hold`. `cash` represents the maximum profit we can achieve when we hold no stock (sell or not buy it), whereas `hold` represents the maximum profit we can achieve when we hold the stock (buy or not sell it).

1. Initialize `cash` to 0 and `hold` to `-prices[0]`. (Initially, we assume that we buy the stock on the first day)
2. Iterate through the `prices` array.
3. In each iteration, we update `cash` as maximum of the current value of `cash` and `hold + price - fee`. This means that we either sell the stock at the current price (subtracting the transaction fee) or don't take any action.
4. Similarly, update `hold` as maximum of current value of `hold` and `cash - price`. This means that we either buy the stock at the current price or don't take any action.
5. After iterating through the entire `prices` array, return the final value of `cash` as the maximum profit.

## A solution in Javascript

```javascript
function maxProfit(prices, fee) {
    let cash = 0, hold = -prices[0];
    for (const price of prices) {
        let temp = cash;
        cash = Math.max(cash, hold + price - fee);
        hold = Math.max(hold, temp - price);
    }
    return cash;
}
```
The algorithm utilizes dynamic programming to solve the problem. We maintain two variables, `cash` and `hold`. `cash` represents the maximum profit we can achieve when we hold no stock (sell or not buy it), whereas `hold` represents the maximum profit we can achieve when we hold the stock (buy or not sell it).

1. Initialize `cash` to 0 and `hold` to `-prices[0]`. (Initially, we assume that we buy the stock on the first day)
2. Iterate through the `prices` array.
3. In each iteration, we update `cash` as maximum of the current value of `cash` and `hold + price - fee`. This means that we either sell the stock at the current price (subtracting the transaction fee) or don't take any action.
4. Similarly, update `hold` as maximum of current value of `hold` and `cash - price`. This means that we either buy the stock at the current price or don't take any action.
5. After iterating through the entire `prices` array, return the final value of `cash` as the maximum profit.


# Max Stack

- slug: max-stack
- difficulty: Hard

Design a max stack data structure that supports the stack operations and supports finding the stack's maximum element.

Implement the `MaxStack` class:

*   `MaxStack()` Initializes the stack object.
*   `void push(int x)` Pushes element `x` onto the stack.
*   `int pop()` Removes the element on top of the stack and returns it.
*   `int top()` Gets the element on the top of the stack without removing it.
*   `int peekMax()` Retrieves the maximum element in the stack without removing it.
*   `int popMax()` Retrieves the maximum element in the stack and removes it. If there is more than one maximum element, only remove the **top-most** one.

You must come up with a solution that supports `O(1)` for each `top` call and `O(logn)` for each other call.

**Example 1:**

**Input**
\[ "MaxStack ",  "push ",  "push ",  "push ",  "top ",  "popMax ",  "top ",  "peekMax ",  "pop ",  "top "\]
\[\[\], \[5\], \[1\], \[5\], \[\], \[\], \[\], \[\], \[\], \[\]\]
**Output**
\[null, null, null, null, 5, 5, 1, 5, 1, 5\]

**Explanation**
MaxStack stk = new MaxStack();
stk.push(5);   // \[**5**\] the top of the stack and the maximum number is 5.
stk.push(1);   // \[5, **1**\] the top of the stack is 1, but the maximum is 5.
stk.push(5);   // \[5, 1, **5**\] the top of the stack is 5, which is also the maximum, because it is the top most one.
stk.top();     // return 5, \[5, 1, **5**\] the stack did not change.
stk.popMax();  // return 5, \[5, **1**\] the stack is changed now, and the top is different from the max.
stk.top();     // return 1, \[5, **1**\] the stack did not change.
stk.peekMax(); // return 5, \[5, **1**\] the stack did not change.
stk.pop();     // return 1, \[**5**\] the top of the stack and the max element is now 5.
stk.top();     // return 5, \[**5**\] the stack did not change.

**Constraints:**

*   `-107 <= x <= 107`
*   At most `105` calls will be made to `push`, `pop`, `top`, `peekMax`, and `popMax`.
*   There will be **at least one element** in the stack when `pop`, `top`, `peekMax`, or `popMax` is called.

## A solution in Java

```java
import java.util.Stack;
import java.util.TreeSet;

class MaxStack {
    Stack<Integer> mainStack;
    TreeSet<Integer> maxSet;

    public MaxStack() {
        mainStack = new Stack<>();
        maxSet = new TreeSet<>();
    }

    public void push(int x) {
        mainStack.push(x);
        maxSet.add(x);
    }

    public int pop() {
        int top = mainStack.pop();
        maxSet.remove(top);
        return top;
    }

    public int top() {
        return mainStack.peek();
    }

    public int peekMax() {
        return maxSet.last();
    }

    public int popMax() {
        int max = maxSet.last();
        maxSet.remove(max);

        Stack<Integer> tempStack = new Stack<>();
        while (mainStack.peek() != max) {
            tempStack.push(mainStack.pop());
        }
        mainStack.pop();
        while (!tempStack.isEmpty()) {
            mainStack.push(tempStack.pop());
        }

        return max;
    }
}
```
The algorithm uses two data structures, a main stack and a max set. The main stack is used to store the elements, and the max set is used to store the maximum elements in a sorted order. When an element is pushed onto the stack, it is added to the main stack and the max set. When the top element of the stack is removed, it is also removed from the max set. To find the maximum element, the last element of the max set is returned. To pop the maximum element, the algorithm first finds the maximum element in the list, removes it from the max set, and then removes it from the stack. If there are multiple maximum elements in the list, only the top-most one is removed. The time complexity for each `top` call is O(1) and for each `push`, `pop`, `peekMax`, and `popMax` call is O(logn).

## A solution in C++

```cpp
#include <set>
#include <stack>

class MaxStack {
    std::stack<int> mainStack;
    std::multiset<int> maxSet;

public:
    MaxStack() {}

    void push(int x) {
        mainStack.push(x);
        maxSet.insert(x);
    }

    int pop() {
        int top = mainStack.top();
        mainStack.pop();
        maxSet.erase(maxSet.find(top));
        return top;
    }

    int top() {
        return mainStack.top();
    }

    int peekMax() {
        return *maxSet.rbegin();
    }

    int popMax() {
        int max = *maxSet.rbegin();
        maxSet.erase(maxSet.find(max));

        std::stack<int> tempStack;
        while (mainStack.top() != max) {
            tempStack.push(mainStack.top());
            mainStack.pop();
        }
        mainStack.pop();
        while (!tempStack.empty()) {
            mainStack.push(tempStack.top());
            tempStack.pop();
        }

        return max;
    }
};
```
The algorithm uses two data structures, a main stack and a max set. The main stack is used to store the elements, and the max set is used to store the maximum elements in a sorted order. When an element is pushed onto the stack, it is added to the main stack and the max set. When the top element of the stack is removed, it is also removed from the max set. To find the maximum element, the last element of the max set is returned. To pop the maximum element, the algorithm first finds the maximum element in the list, removes it from the max set, and then removes it from the stack. If there are multiple maximum elements in the list, only the top-most one is removed. The time complexity for each `top` call is O(1) and for each `push`, `pop`, `peekMax`, and `popMax` call is O(logn).

## A solution in Python

```python
from sortedcontainers import SortedList

class MaxStack:
    def __init__(self):
        self.mainStack = []
        self.maxSet = SortedList()

    def push(self, x: int) -> None:
        self.mainStack.append(x)
        self.maxSet.add(x)

    def pop(self) -> int:
        top = self.mainStack.pop()
        self.maxSet.remove(top)
        return top

    def top(self) -> int:
        return self.mainStack[-1]

    def peekMax(self) -> int:
        return self.maxSet[-1]

    def popMax(self) -> int:
        max_val = self.maxSet.pop()
        tempStack = []
        while self.mainStack[-1] != max_val:
            tempStack.append(self.mainStack.pop())
        self.mainStack.pop()
        while tempStack:
            self.mainStack.append(tempStack.pop())
        return max_val
```
The algorithm uses two data structures, a main stack and a max set. The main stack is used to store the elements, and the max set is used to store the maximum elements in a sorted order. When an element is pushed onto the stack, it is added to the main stack and the max set. When the top element of the stack is removed, it is also removed from the max set. To find the maximum element, the last element of the max set is returned. To pop the maximum element, the algorithm first finds the maximum element in the list, removes it from the max set, and then removes it from the stack. If there are multiple maximum elements in the list, only the top-most one is removed. The time complexity for each `top` call is O(1) and for each `push`, `pop`, `peekMax`, and `popMax` call is O(logn).

## A solution in Javascript

```javascript
class MaxStack {
    constructor() {
        this.mainStack = [];
        this.maxSet = new Set();
    }

    push(x) {
        this.mainStack.push(x);
        this.maxSet.add(x);
    }

    pop() {
        const top = this.mainStack.pop();
        this.maxSet.delete(top);
        return top;
    }

    top() {
        return this.mainStack[this.mainStack.length - 1];
    }

    peekMax() {
        return Math.max(...this.maxSet);
    }

    popMax() {
        const max = Math.max(...this.maxSet);
        this.maxSet.delete(max);

        const tempStack = [];
        while (this.mainStack[this.mainStack.length - 1] !== max) {
            tempStack.push(this.mainStack.pop());
        }
        this.mainStack.pop();
        while (tempStack.length) {
            this.mainStack.push(tempStack.pop());
        }

        return max;
    }
}
```
The algorithm uses two data structures, a main stack and a max set. The main stack is used to store the elements, and the max set is used to store the maximum elements in a sorted order. When an element is pushed onto the stack, it is added to the main stack and the max set. When the top element of the stack is removed, it is also removed from the max set. To find the maximum element, the last element of the max set is returned. To pop the maximum element, the algorithm first finds the maximum element in the list, removes it from the max set, and then removes it from the stack. If there are multiple maximum elements in the list, only the top-most one is removed. The time complexity for each `top` call is O(1) and for each `push`, `pop`, `peekMax`, and `popMax` call is O(logn).


# 1-bit and 2-bit Characters

- slug: 1-bit-and-2-bit-characters
- difficulty: Easy

We have two special characters:

*   The first character can be represented by one bit `0`.
*   The second character can be represented by two bits (`10` or `11`).

Given a binary array `bits` that ends with `0`, return `true` if the last character must be a one-bit character.

**Example 1:**

**Input:** bits = \[1,0,0\]
**Output:** true
**Explanation:** The only way to decode it is two-bit character and one-bit character.
So the last character is one-bit character.

**Example 2:**

**Input:** bits = \[1,1,1,0\]
**Output:** false
**Explanation:** The only way to decode it is two-bit character and two-bit character.
So the last character is not one-bit character.

**Constraints:**

*   `1 <= bits.length <= 1000`
*   `bits[i]` is either `0` or `1`.

## A solution in Java

```java
boolean isOneBitCharacter(int[] bits) {
    int i;
    for (i = 0; i < bits.length - 1; i++) {
        i += bits[i];
    }
    return i == bits.length - 1;
}
```
The algorithm iterates through the binary array `bits`. If the current element is 1, the next character will be a 2-bit character, so the index `i` will be incremented by 2 (1 from the current iteration and 1 from the 2-bit character). If the current element is 0, it means that the current character is a 1-bit character, so the index `i` is incremented by 1 (from the current iteration). The loop ends either when reaching the last character or when going beyond it.

After the loop, if `i` is equal to the last index of the array (i.e., `bits.size() - 1`, `bits.length - 1`, or `len(bits) - 1` depending on the language), it means the last character is a 1-bit character, and the function returns `true`. Otherwise, it returns `false`.

## A solution in C++

```cpp
bool isOneBitCharacter(std::vector<int>& bits) {
    int i;
    for (i = 0; i < bits.size() - 1; i++) {
        i += bits[i];
    }
    return i == bits.size() - 1;
}
```
The algorithm iterates through the binary array `bits`. If the current element is 1, the next character will be a 2-bit character, so the index `i` will be incremented by 2 (1 from the current iteration and 1 from the 2-bit character). If the current element is 0, it means that the current character is a 1-bit character, so the index `i` is incremented by 1 (from the current iteration). The loop ends either when reaching the last character or when going beyond it.

After the loop, if `i` is equal to the last index of the array (i.e., `bits.size() - 1`, `bits.length - 1`, or `len(bits) - 1` depending on the language), it means the last character is a 1-bit character, and the function returns `true`. Otherwise, it returns `false`.

## A solution in Python

```python
def is_one_bit_character(bits):
    i = 0
    while i < len(bits) - 1:
        i += bits[i] + 1
    return i == len(bits) - 1
```
The algorithm iterates through the binary array `bits`. If the current element is 1, the next character will be a 2-bit character, so the index `i` will be incremented by 2 (1 from the current iteration and 1 from the 2-bit character). If the current element is 0, it means that the current character is a 1-bit character, so the index `i` is incremented by 1 (from the current iteration). The loop ends either when reaching the last character or when going beyond it.

After the loop, if `i` is equal to the last index of the array (i.e., `bits.size() - 1`, `bits.length - 1`, or `len(bits) - 1` depending on the language), it means the last character is a 1-bit character, and the function returns `true`. Otherwise, it returns `false`.

## A solution in Javascript

```javascript
function isOneBitCharacter(bits) {
    let i;
    for (i = 0; i < bits.length - 1; i++) {
        i += bits[i];
    }
    return i === bits.length - 1;
}
```
The algorithm iterates through the binary array `bits`. If the current element is 1, the next character will be a 2-bit character, so the index `i` will be incremented by 2 (1 from the current iteration and 1 from the 2-bit character). If the current element is 0, it means that the current character is a 1-bit character, so the index `i` is incremented by 1 (from the current iteration). The loop ends either when reaching the last character or when going beyond it.

After the loop, if `i` is equal to the last index of the array (i.e., `bits.size() - 1`, `bits.length - 1`, or `len(bits) - 1` depending on the language), it means the last character is a 1-bit character, and the function returns `true`. Otherwise, it returns `false`.


# Maximum Length of Repeated Subarray

- slug: maximum-length-of-repeated-subarray
- difficulty: Medium

Given two integer arrays `nums1` and `nums2`, return _the maximum length of a subarray that appears in **both** arrays_.

**Example 1:**

**Input:** nums1 = \[1,2,3,2,1\], nums2 = \[3,2,1,4,7\]
**Output:** 3
**Explanation:** The repeated subarray with maximum length is \[3,2,1\].

**Example 2:**

**Input:** nums1 = \[0,0,0,0,0\], nums2 = \[0,0,0,0,0\]
**Output:** 5
**Explanation:** The repeated subarray with maximum length is \[0,0,0,0,0\].

**Constraints:**

*   `1 <= nums1.length, nums2.length <= 1000`
*   `0 <= nums1[i], nums2[i] <= 100`

## A solution in Java

```java
public int findLength(int[] nums1, int[] nums2) {
    int m = nums1.length;
    int n = nums2.length;
    int[][] dp = new int[m + 1][n + 1];
    int maxLength = 0;

    for (int i = m - 1; i >= 0; i--) {
        for (int j = n - 1; j >= 0; j--) {
            if (nums1[i] == nums2[j]) {
                dp[i][j] = dp[i + 1][j + 1] + 1;
                maxLength = Math.max(maxLength, dp[i][j]);
            }
        }
    }

    return maxLength;
}
```
The algorithm uses dynamic programming to store the length of the common subarray ending at the current position for both arrays. For each element in the input arrays, it checks if the elements are equal. If they are, it updates the length of their common subarray by adding 1 to the length of the common subarray found in the next positions. Finally, the maximum length found is returned.

Note that the outer loop iterates from the end to the beginning, avoiding the need to initialize values in the table with special cases (like initializing with the maximum length at the beginning of the loop). This makes the code shorter and easier to understand. Each step of the iteration compares elements in the two arrays and updates the maxLength, if necessary.

## A solution in C++

```cpp
int findLength(vector<int>& nums1, vector<int>& nums2) {
    int m = nums1.size();
    int n = nums2.size();
    vector<vector<int>> dp(m + 1, vector<int>(n + 1, 0));
    int maxLength = 0;

    for (int i = m - 1; i >= 0; i--) {
        for (int j = n - 1; j >= 0; j--) {
            if (nums1[i] == nums2[j]) {
                dp[i][j] = dp[i + 1][j + 1] + 1;
                maxLength = max(maxLength, dp[i][j]);
            }
        }
    }

    return maxLength;
}
```
The algorithm uses dynamic programming to store the length of the common subarray ending at the current position for both arrays. For each element in the input arrays, it checks if the elements are equal. If they are, it updates the length of their common subarray by adding 1 to the length of the common subarray found in the next positions. Finally, the maximum length found is returned.

Note that the outer loop iterates from the end to the beginning, avoiding the need to initialize values in the table with special cases (like initializing with the maximum length at the beginning of the loop). This makes the code shorter and easier to understand. Each step of the iteration compares elements in the two arrays and updates the maxLength, if necessary.

## A solution in Python

```python
def findLength(nums1, nums2):
    m, n = len(nums1), len(nums2)
    dp = [[0] * (n + 1) for _ in range(m + 1)]
    maxLength = 0

    for i in range(m - 1, -1, -1):
        for j in range(n - 1, -1, -1):
            if nums1[i] == nums2[j]:
                dp[i][j] = dp[i + 1][j + 1] + 1
                maxLength = max(maxLength, dp[i][j])

    return maxLength
```
The algorithm uses dynamic programming to store the length of the common subarray ending at the current position for both arrays. For each element in the input arrays, it checks if the elements are equal. If they are, it updates the length of their common subarray by adding 1 to the length of the common subarray found in the next positions. Finally, the maximum length found is returned.

Note that the outer loop iterates from the end to the beginning, avoiding the need to initialize values in the table with special cases (like initializing with the maximum length at the beginning of the loop). This makes the code shorter and easier to understand. Each step of the iteration compares elements in the two arrays and updates the maxLength, if necessary.

## A solution in Javascript

```javascript
function findLength(nums1, nums2) {
    const m = nums1.length;
    const n = nums2.length;
    const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0));
    let maxLength = 0;

    for (let i = m - 1; i >= 0; i--) {
        for (let j = n - 1; j >= 0; j--) {
            if (nums1[i] === nums2[j]) {
                dp[i][j] = dp[i + 1][j + 1] + 1;
                maxLength = Math.max(maxLength, dp[i][j]);
            }
        }
    }

    return maxLength;
}
```
The algorithm uses dynamic programming to store the length of the common subarray ending at the current position for both arrays. For each element in the input arrays, it checks if the elements are equal. If they are, it updates the length of their common subarray by adding 1 to the length of the common subarray found in the next positions. Finally, the maximum length found is returned.

Note that the outer loop iterates from the end to the beginning, avoiding the need to initialize values in the table with special cases (like initializing with the maximum length at the beginning of the loop). This makes the code shorter and easier to understand. Each step of the iteration compares elements in the two arrays and updates the maxLength, if necessary.


# Find K-th Smallest Pair Distance

- slug: find-k-th-smallest-pair-distance
- difficulty: Hard

The **distance of a pair** of integers `a` and `b` is defined as the absolute difference between `a` and `b`.

Given an integer array `nums` and an integer `k`, return _the_ `kth` _smallest **distance among all the pairs**_ `nums[i]` _and_ `nums[j]` _where_ `0 <= i < j < nums.length`.

**Example 1:**

**Input:** nums = \[1,3,1\], k = 1
**Output:** 0
**Explanation:** Here are all the pairs:
(1,3) -> 2
(1,1) -> 0
(3,1) -> 2
Then the 1st smallest distance pair is (1,1), and its distance is 0.

**Example 2:**

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

**Example 3:**

**Input:** nums = \[1,6,1\], k = 3
**Output:** 5

**Constraints:**

*   `n == nums.length`
*   `2 <= n <= 104`
*   `0 <= nums[i] <= 106`
*   `1 <= k <= n * (n - 1) / 2`

## A solution in Java

```java
import java.util.Arrays;

public int smallestDistancePair(int[] nums, int k) {
    Arrays.sort(nums);
    int low = 0, high = nums[nums.length - 1] - nums[0];

    while (low < high) {
        int mid = (low + high) / 2;
        int count = 0, left = 0;

        for (int right = 0; right < nums.length; ++right) {
            while (nums[right] - nums[left] > mid) {
                ++left;
            }
            count += (right - left);
        }

        if (count < k) {
            low = mid + 1;
        } else {
            high = mid;
        }
    }

    return low;
}
```
The algorithm works as follows:
1. Sort the input array `nums`.
2. Initialize the search range for the kth smallest distance with `low` as 0 and `high` as the maximum possible distance in the array (i.e., the difference between the last element and the first element).
3. While `low` is smaller than `high`, perform a binary-search-like technique:
   a. Calculate the middle distance `mid` between `low` and `high`.
   b. Initialize `count` and `left` pointers to 0.
   c. Traverse the array using a `right` pointer.
   d. Move the `left` pointer to the right as long as the distance between `nums[right]` and `nums[left]` is greater than `mid`.
   e. Increment the `count` by the difference between `right` and `left`.
   f. If the `count` is smaller than `k`, update `low` to `mid + 1`. Otherwise, update `high` to `mid`.
4. When the loop ends, `low` will hold the kth smallest distance.

## A solution in C++

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

int smallestDistancePair(std::vector<int>& nums, int k) {
    std::sort(nums.begin(), nums.end());
    int low = 0, high = nums.back() - nums.front();

    while (low < high) {
        int mid = (low + high) / 2;
        int count = 0, left = 0;

        for (int right = 0; right < nums.size(); ++right) {
            while (nums[right] - nums[left] > mid) {
                ++left;
            }
            count += (right - left);
        }

        if (count < k) {
            low = mid + 1;
        } else {
            high = mid;
        }
    }

    return low;
}
```
The algorithm works as follows:
1. Sort the input array `nums`.
2. Initialize the search range for the kth smallest distance with `low` as 0 and `high` as the maximum possible distance in the array (i.e., the difference between the last element and the first element).
3. While `low` is smaller than `high`, perform a binary-search-like technique:
   a. Calculate the middle distance `mid` between `low` and `high`.
   b. Initialize `count` and `left` pointers to 0.
   c. Traverse the array using a `right` pointer.
   d. Move the `left` pointer to the right as long as the distance between `nums[right]` and `nums[left]` is greater than `mid`.
   e. Increment the `count` by the difference between `right` and `left`.
   f. If the `count` is smaller than `k`, update `low` to `mid + 1`. Otherwise, update `high` to `mid`.
4. When the loop ends, `low` will hold the kth smallest distance.

## A solution in Python

```python
def smallestDistancePair(nums, k):
    nums.sort()
    low, high = 0, nums[-1] - nums[0]

    while low < high:
        mid = (low + high) // 2
        count, left = 0, 0

        for right in range(len(nums)):
            while nums[right] - nums[left] > mid:
                left += 1
            count += (right - left)

        if count < k:
            low = mid + 1
        else:
            high = mid

    return low
```
The algorithm works as follows:
1. Sort the input array `nums`.
2. Initialize the search range for the kth smallest distance with `low` as 0 and `high` as the maximum possible distance in the array (i.e., the difference between the last element and the first element).
3. While `low` is smaller than `high`, perform a binary-search-like technique:
   a. Calculate the middle distance `mid` between `low` and `high`.
   b. Initialize `count` and `left` pointers to 0.
   c. Traverse the array using a `right` pointer.
   d. Move the `left` pointer to the right as long as the distance between `nums[right]` and `nums[left]` is greater than `mid`.
   e. Increment the `count` by the difference between `right` and `left`.
   f. If the `count` is smaller than `k`, update `low` to `mid + 1`. Otherwise, update `high` to `mid`.
4. When the loop ends, `low` will hold the kth smallest distance.

## A solution in Javascript

```javascript
function smallestDistancePair(nums, k) {
    nums.sort((a, b) => a - b);
    let low = 0, high = nums[nums.length - 1] - nums[0];

    while (low < high) {
        let mid = Math.floor((low + high) / 2);
        let count = 0, left = 0;

        for (let right = 0; right < nums.length; ++right) {
            while (nums[right] - nums[left] > mid) {
                ++left;
            }
            count += (right - left);
        }

        if (count < k) {
            low = mid + 1;
        } else {
            high = mid;
        }
    }

    return low;
}
```
The algorithm works as follows:
1. Sort the input array `nums`.
2. Initialize the search range for the kth smallest distance with `low` as 0 and `high` as the maximum possible distance in the array (i.e., the difference between the last element and the first element).
3. While `low` is smaller than `high`, perform a binary-search-like technique:
   a. Calculate the middle distance `mid` between `low` and `high`.
   b. Initialize `count` and `left` pointers to 0.
   c. Traverse the array using a `right` pointer.
   d. Move the `left` pointer to the right as long as the distance between `nums[right]` and `nums[left]` is greater than `mid`.
   e. Increment the `count` by the difference between `right` and `left`.
   f. If the `count` is smaller than `k`, update `low` to `mid + 1`. Otherwise, update `high` to `mid`.
4. When the loop ends, `low` will hold the kth smallest distance.


# Longest Word in Dictionary

- slug: longest-word-in-dictionary
- difficulty: Medium

Given an array of strings `words` representing an English Dictionary, return _the longest word in_ `words` _that can be built one character at a time by other words in_ `words`.

If there is more than one possible answer, return the longest word with the smallest lexicographical order. If there is no answer, return the empty string.

Note that the word should be built from left to right with each additional character being added to the end of a previous word.

**Example 1:**

**Input:** words = \[ "w ", "wo ", "wor ", "worl ", "world "\]
**Output:**  "world "
**Explanation:** The word  "world " can be built one character at a time by  "w ",  "wo ",  "wor ", and  "worl ".

**Example 2:**

**Input:** words = \[ "a ", "banana ", "app ", "appl ", "ap ", "apply ", "apple "\]
**Output:**  "apple "
**Explanation:** Both  "apply " and  "apple " can be built from other words in the dictionary. However,  "apple " is lexicographically smaller than  "apply ".

**Constraints:**

*   `1 <= words.length <= 1000`
*   `1 <= words[i].length <= 30`
*   `words[i]` consists of lowercase English letters.

## A solution in Java

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

class Solution {
    public String longestWord(String[] words) {
        Arrays.sort(words);
        Set<String> builtWords = new HashSet<>();
        String result = "";

        for (String word : words) {
            if (word.length() == 1 || builtWords.contains(word.substring(0, word.length() - 1))) {
                result = (word.length() > result.length()) ? word : result;
                builtWords.add(word);
            }
        }

        return result;
    }
}
```
The algorithm starts by sorting the input list of words. Then, it initializes an empty set `built_words` to store the "buildable" words and an empty string `result` to keep track of the longest word found.

For each word in the sorted list, it checks if the word is buildable by having the length of 1 or its substring without the last character is in the set `built_words`. If the word is buildable, it compares its length with the current `result` and updates the `result` if the word is longer. It also adds the buildable word to the set `built_words`.

After iterating through all the words in the list, it returns the longest buildable word found.

## A solution in C++

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

std::string longestWord(std::vector<std::string>& words) {
    std::sort(words.begin(), words.end());
    std::set<std::string> built_words;
    std::string result = "";

    for (const auto& word : words) {
        if (word.size() == 1 || built_words.find(word.substr(0, word.size() - 1)) != built_words.end()) {
            result = (word.size() > result.size()) ? word : result;
            built_words.insert(word);
        }
    }

    return result;
}
```
The algorithm starts by sorting the input list of words. Then, it initializes an empty set `built_words` to store the "buildable" words and an empty string `result` to keep track of the longest word found.

For each word in the sorted list, it checks if the word is buildable by having the length of 1 or its substring without the last character is in the set `built_words`. If the word is buildable, it compares its length with the current `result` and updates the `result` if the word is longer. It also adds the buildable word to the set `built_words`.

After iterating through all the words in the list, it returns the longest buildable word found.

## A solution in Python

```python
def longest_word(words):
    built_words = set()
    result = ''

    for word in sorted(words):
        if len(word) == 1 or word[:-1] in built_words:
            if len(word) > len(result):
                result = word
            built_words.add(word)

    return result
```
The algorithm starts by sorting the input list of words. Then, it initializes an empty set `built_words` to store the "buildable" words and an empty string `result` to keep track of the longest word found.

For each word in the sorted list, it checks if the word is buildable by having the length of 1 or its substring without the last character is in the set `built_words`. If the word is buildable, it compares its length with the current `result` and updates the `result` if the word is longer. It also adds the buildable word to the set `built_words`.

After iterating through all the words in the list, it returns the longest buildable word found.

## A solution in Javascript

```javascript
function longestWord(words) {
    words.sort();
    const builtWords = new Set();
    let result = '';

    for (const word of words) {
        if (word.length === 1 || builtWords.has(word.slice(0, -1))) {
            result = (word.length > result.length) ? word : result;
            builtWords.add(word);
        }
    }

    return result;
}
```
The algorithm starts by sorting the input list of words. Then, it initializes an empty set `built_words` to store the "buildable" words and an empty string `result` to keep track of the longest word found.

For each word in the sorted list, it checks if the word is buildable by having the length of 1 or its substring without the last character is in the set `built_words`. If the word is buildable, it compares its length with the current `result` and updates the `result` if the word is longer. It also adds the buildable word to the set `built_words`.

After iterating through all the words in the list, it returns the longest buildable word found.


# Accounts Merge

- slug: accounts-merge
- difficulty: Medium

Given a list of `accounts` where each element `accounts[i]` is a list of strings, where the first element `accounts[i][0]` is a name, and the rest of the elements are **emails** representing emails of the account.

Now, we would like to merge these accounts. Two accounts definitely belong to the same person if there is some common email to both accounts. Note that even if two accounts have the same name, they may belong to different people as people could have the same name. A person can have any number of accounts initially, but all of their accounts definitely have the same name.

After merging the accounts, return the accounts in the following format: the first element of each account is the name, and the rest of the elements are emails **in sorted order**. The accounts themselves can be returned in **any order**.

**Example 1:**

**Input:** accounts = \[\[ "John ", "johnsmith@mail.com ", "john\_newyork@mail.com "\],\[ "John ", "johnsmith@mail.com ", "john00@mail.com "\],\[ "Mary ", "mary@mail.com "\],\[ "John ", "johnnybravo@mail.com "\]\]
**Output:** \[\[ "John ", "john00@mail.com ", "john\_newyork@mail.com ", "johnsmith@mail.com "\],\[ "Mary ", "mary@mail.com "\],\[ "John ", "johnnybravo@mail.com "\]\]
**Explanation:**
The first and second John's are the same person as they have the common email  "johnsmith@mail.com ".
The third John and Mary are different people as none of their email addresses are used by other accounts.
We could return these lists in any order, for example the answer \[\['Mary', 'mary@mail.com'\], \['John', 'johnnybravo@mail.com'\],
\['John', 'john00@mail.com', 'john\_newyork@mail.com', 'johnsmith@mail.com'\]\] would still be accepted.

**Example 2:**

**Input:** accounts = \[\[ "Gabe ", "Gabe0@m.co ", "Gabe3@m.co ", "Gabe1@m.co "\],\[ "Kevin ", "Kevin3@m.co ", "Kevin5@m.co ", "Kevin0@m.co "\],\[ "Ethan ", "Ethan5@m.co ", "Ethan4@m.co ", "Ethan0@m.co "\],\[ "Hanzo ", "Hanzo3@m.co ", "Hanzo1@m.co ", "Hanzo0@m.co "\],\[ "Fern ", "Fern5@m.co ", "Fern1@m.co ", "Fern0@m.co "\]\]
**Output:** \[\[ "Ethan ", "Ethan0@m.co ", "Ethan4@m.co ", "Ethan5@m.co "\],\[ "Gabe ", "Gabe0@m.co ", "Gabe1@m.co ", "Gabe3@m.co "\],\[ "Hanzo ", "Hanzo0@m.co ", "Hanzo1@m.co ", "Hanzo3@m.co "\],\[ "Kevin ", "Kevin0@m.co ", "Kevin3@m.co ", "Kevin5@m.co "\],\[ "Fern ", "Fern0@m.co ", "Fern1@m.co ", "Fern5@m.co "\]\]

**Constraints:**

*   `1 <= accounts.length <= 1000`
*   `2 <= accounts[i].length <= 10`
*   `1 <= accounts[i][j].length <= 30`
*   `accounts[i][0]` consists of English letters.
*   `accounts[i][j] (for j > 0)` is a valid email.

## A solution in Java

```java
import java.util.*;

public List<List<String>> accountsMerge(List<List<String>> accounts) {
    Map<String, Integer> emailToId = new HashMap<>();
    for (int i = 0; i < accounts.size(); ++i) {
        for (int j = 1; j < accounts.get(i).size(); ++j) {
            emailToId.put(accounts.get(i).get(j), i);
        }
    }

    List<List<String>> result = new ArrayList<>();
    boolean[] visited = new boolean[accounts.size()];
    for (int i = 0; i < accounts.size(); ++i) {
        if (!visited[i]) {
            Set<String> mergedEmails = new HashSet<>();
            dfs(i, accounts, visited, mergedEmails, emailToId);
            List<String> mergedAccount = new ArrayList<>(mergedEmails);
            Collections.sort(mergedAccount);
            mergedAccount.add(0, accounts.get(i).get(0));
            result.add(mergedAccount);
        }
    }
    return result;
}

private void dfs(int id, List<List<String>> accounts, boolean[] visited, Set<String> mergedEmails, Map<String, Integer> emailToId) {
    if (visited[id]) return;
    visited[id] = true;
    for (int j = 1; j < accounts.get(id).size(); ++j) {
        String email = accounts.get(id).get(j);
        mergedEmails.add(email);
        int nextId = emailToId.get(email);
        dfs(nextId, accounts, visited, mergedEmails, emailToId);
    }
}
```
The algorithm uses a depth-first search (DFS) to merge accounts with the same email. It starts by creating a dictionary `email_to_id` to map email addresses to the account ID. Then, a visited set records visited account IDs. For each unvisited account ID, DFS is used to traverse and collect all the connected email addresses in the merged set. The result is formed by appending the sorted merged email addresses to the account's name. The final result contains all the merged accounts.

## A solution in C++

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

using namespace std;

void dfs(int id, const vector<vector<string>>& accounts, vector<bool>& visited, set<string>& merged_emails, map<string, int>& email_to_id) {
    if (visited[id]) return;
    visited[id] = true;
    for (int j = 1; j < accounts[id].size(); ++j) {
        const string& email = accounts[id][j];
        merged_emails.insert(email);
        int next_id = email_to_id[email];
        dfs(next_id, accounts, visited, merged_emails, email_to_id);
    }
}

vector<vector<string>> accountsMerge(vector<vector<string>>& accounts) {
    map<string, int> email_to_id;
    for (int i = 0; i < accounts.size(); ++i)
        for (int j = 1; j < accounts[i].size(); ++j)
            email_to_id[accounts[i][j]] = i;

    vector<vector<string>> result;
    vector<bool> visited(accounts.size(), false);
    for (int i = 0; i < accounts.size(); ++i) {
        if (!visited[i]) {
            set<string> merged_emails;
            dfs(i, accounts, visited, merged_emails, email_to_id);
            vector<string> merged_account(merged_emails.begin(), merged_emails.end());
            merged_account.insert(merged_account.begin(), accounts[i][0]);
            result.push_back(merged_account);
        }
    }
    return result;
}
```
The algorithm uses a depth-first search (DFS) to merge accounts with the same email. It starts by creating a dictionary `email_to_id` to map email addresses to the account ID. Then, a visited set records visited account IDs. For each unvisited account ID, DFS is used to traverse and collect all the connected email addresses in the merged set. The result is formed by appending the sorted merged email addresses to the account's name. The final result contains all the merged accounts.

## A solution in Python

```python
from collections import defaultdict

def accountsMerge(accounts):
    def dfs(id, visited, merged_emails):
        if id in visited:
            return
        visited.add(id)
        for email in accounts[id][1:]:
            merged_emails.add(email)
            dfs(email_to_id[email], visited, merged_emails)

    email_to_id = {}
    for i, account in enumerate(accounts):
        for email in account[1:]:
            email_to_id[email] = i

    result = []
    visited = set()
    for i, account in enumerate(accounts):
        if i not in visited:
            merged_emails = set()
            dfs(i, visited, merged_emails)
            result.append([account[0]] + sorted(merged_emails))
    return result
```
The algorithm uses a depth-first search (DFS) to merge accounts with the same email. It starts by creating a dictionary `email_to_id` to map email addresses to the account ID. Then, a visited set records visited account IDs. For each unvisited account ID, DFS is used to traverse and collect all the connected email addresses in the merged set. The result is formed by appending the sorted merged email addresses to the account's name. The final result contains all the merged accounts.

## A solution in Javascript

```javascript
var accountsMerge = function(accounts) {
    function dfs(id, visited, mergedEmails) {
        if (visited.has(id)) return;
        visited.add(id);
        for (let j = 1; j < accounts[id].length; j++) {
            const email = accounts[id][j];
            mergedEmails.add(email);
            const nextId = emailToId[email];
            dfs(nextId, visited, mergedEmails);
        }
    }

    const emailToId = {};
    accounts.forEach((account, i) => {
        account.slice(1).forEach(email => {
            emailToId[email] = i;
        });
    });

    const result = [];
    const visited = new Set();
    accounts.forEach((account, i) => {
        if (!visited.has(i)) {
            const mergedEmails = new Set();
            dfs(i, visited, mergedEmails);
            result.push([account[0], ...Array.from(mergedEmails).sort()]);
        }
    });
    return result;
};
```
The algorithm uses a depth-first search (DFS) to merge accounts with the same email. It starts by creating a dictionary `email_to_id` to map email addresses to the account ID. Then, a visited set records visited account IDs. For each unvisited account ID, DFS is used to traverse and collect all the connected email addresses in the merged set. The result is formed by appending the sorted merged email addresses to the account's name. The final result contains all the merged accounts.


# Remove Comments

- slug: remove-comments
- difficulty: Medium

Given a C++ program, remove comments from it. The program source is an array of strings `source` where `source[i]` is the `ith` line of the source code. This represents the result of splitting the original source code string by the newline character `'\n'`.

In C++, there are two types of comments, line comments, and block comments.

*   The string `"// "` denotes a line comment, which represents that it and the rest of the characters to the right of it in the same line should be ignored.
*   The string `"/* "` denotes a block comment, which represents that all characters until the next (non-overlapping) occurrence of `"*/ "` should be ignored. (Here, occurrences happen in reading order: line by line from left to right.) To be clear, the string `"/*/ "` does not yet end the block comment, as the ending would be overlapping the beginning.

The first effective comment takes precedence over others.

*   For example, if the string `"// "` occurs in a block comment, it is ignored.
*   Similarly, if the string `"/* "` occurs in a line or block comment, it is also ignored.

If a certain line of code is empty after removing comments, you must not output that line: each string in the answer list will be non-empty.

There will be no control characters, single quote, or double quote characters.

*   For example, `source = "string s = "/* Not a comment. */ "; "` will not be a test case.

Also, nothing else such as defines or macros will interfere with the comments.

It is guaranteed that every open block comment will eventually be closed, so `"/* "` outside of a line or block comment always starts a new comment.

Finally, implicit newline characters can be deleted by block comments. Please see the examples below for details.

After removing the comments from the source code, return _the source code in the same format_.

**Example 1:**

**Input:** source = \[ "/\*Test program \*/ ",  "int main() ",  "{  ",  "  // variable declaration  ",  "int a, b, c; ",  "/\* This is a test ",  "   multiline   ",  "   comment for  ",  "   testing \*/ ",  "a = b + c; ",  "} "\]
**Output:** \[ "int main() ", "{  ", "   ", "int a, b, c; ", "a = b + c; ", "} "\]
**Explanation:** The line by line code is visualized as below:
/\*Test program \*/
int main()
{
  // variable declaration
int a, b, c;
/\* This is a test
   multiline
   comment for
   testing \*/
a = b + c;
}
The string /\* denotes a block comment, including line 1 and lines 6-9. The string // denotes line 4 as comments.
The line by line output code is visualized as below:
int main()
{

int a, b, c;
a = b + c;
}

**Example 2:**

**Input:** source = \[ "a/\*comment ",  "line ",  "more\_comment\*/b "\]
**Output:** \[ "ab "\]
**Explanation:** The original source string is  "a/\*comment\\nline\\nmore\_comment\*/b ", where we have bolded the newline characters.  After deletion, the implicit newline characters are deleted, leaving the string  "ab ", which when delimited by newline characters becomes \[ "ab "\].

**Constraints:**

*   `1 <= source.length <= 100`
*   `0 <= source[i].length <= 80`
*   `source[i]` consists of printable **ASCII** characters.
*   Every open block comment is eventually closed.
*   There are no single-quote or double-quote in the input.

## A solution in Java

```java
public List<String> removeComments(String[] source) {
    List<String> result = new ArrayList<>();
    StringBuilder buffer = new StringBuilder();
    boolean inBlockComment = false;

    for (String line : source) {
        for (int i = 0; i < line.length(); ++i) {
            if (inBlockComment) {
                if (i < line.length() - 1 && line.charAt(i) == '*' && line.charAt(i + 1) == '/') {
                    inBlockComment = false;
                    ++i;
                }
            } else {
                if (i < line.length() - 1 && line.charAt(i) == '/' && line.charAt(i + 1) == '*') {
                    inBlockComment = true;
                    ++i;
                } else if (i < line.length() - 1 && line.charAt(i) == '/' && line.charAt(i + 1) == '/') {
                    break;
                } else {
                    buffer.append(line.charAt(i));
                }
            }
        }
        if (!inBlockComment && buffer.length() > 0) {
            result.add(buffer.toString());
            buffer.setLength(0);
        }
    }
    return result;
}
```
The algorithm begins by initializing an empty result list, an empty buffer string or list, and a boolean variable `in_block_comment` set to `false`. Then, for each line in the source code, we iterate through the characters of the line. The algorithm checks if we are within a block comment or not. If so, it looks for the block comment end combination (`*/`) and sets `in_block_comment` to `false` if found, skipping the end combination characters.

If not in a block comment, the algorithm checks for the beginning of a block comment (`/*`) and sets the `in_block_comment` variable to `true`. If a line comment start (`//`) is found, it breaks the inner loop to skip the rest of the line since line comments end at the end of the line, making the rest of the line irrelevant. Otherwise, the algorithm appends the current character to the `buffer`.

After processing a line, if not in a block comment and the buffer is not empty, the content of the buffer is added to the result list, and the buffer is cleared.

Once all lines have been processed, the function returns the result list. The implementation remains mostly the same across all four languages, with slight variations due to the respective language syntax.

## A solution in C++

```cpp
vector<string> removeComments(vector<string>& source) {
    vector<string> result;
    string buffer;
    bool in_block_comment = false;

    for (const auto& line : source) {
        for (size_t i = 0; i < line.size(); ++i) {
            if (in_block_comment) {
                if (i < line.size() - 1 && line[i] == '*' && line[i + 1] == '/') {
                    in_block_comment = false;
                    ++i;
                }
            } else {
                if (i < line.size() - 1 && line[i] == '/' && line[i + 1] == '*') {
                    in_block_comment = true;
                    ++i;
                } else if (i < line.size() - 1 && line[i] == '/' && line[i + 1] == '/') {
                    break;
                } else {
                    buffer.push_back(line[i]);
                }
            }
        }
        if (!in_block_comment && !buffer.empty()) {
            result.push_back(buffer);
            buffer.clear();
        }
    }
    return result;
}
```
The algorithm begins by initializing an empty result list, an empty buffer string or list, and a boolean variable `in_block_comment` set to `false`. Then, for each line in the source code, we iterate through the characters of the line. The algorithm checks if we are within a block comment or not. If so, it looks for the block comment end combination (`*/`) and sets `in_block_comment` to `false` if found, skipping the end combination characters.

If not in a block comment, the algorithm checks for the beginning of a block comment (`/*`) and sets the `in_block_comment` variable to `true`. If a line comment start (`//`) is found, it breaks the inner loop to skip the rest of the line since line comments end at the end of the line, making the rest of the line irrelevant. Otherwise, the algorithm appends the current character to the `buffer`.

After processing a line, if not in a block comment and the buffer is not empty, the content of the buffer is added to the result list, and the buffer is cleared.

Once all lines have been processed, the function returns the result list. The implementation remains mostly the same across all four languages, with slight variations due to the respective language syntax.

## A solution in Python

```python
def removeComments(self, source: List[str]) -> List[str]:
    result = []
    buffer = []
    in_block_comment = False

    for line in source:
        i = 0
        while i < len(line):
            if in_block_comment:
                if i < len(line) - 1 and line[i] == '*' and line[i + 1] == '/':
                    in_block_comment = False
                    i += 1
            else:
                if i < len(line) - 1 and line[i] == '/' and line[i + 1] == '*':
                    in_block_comment = True
                    i += 1
                elif i < len(line) - 1 and line[i] == '/' and line[i + 1] == '/':
                    break
                else:
                    buffer.append(line[i])
            i += 1

        if not in_block_comment and buffer:
            result.append(''.join(buffer))
            buffer.clear()

    return result
```
The algorithm begins by initializing an empty result list, an empty buffer string or list, and a boolean variable `in_block_comment` set to `false`. Then, for each line in the source code, we iterate through the characters of the line. The algorithm checks if we are within a block comment or not. If so, it looks for the block comment end combination (`*/`) and sets `in_block_comment` to `false` if found, skipping the end combination characters.

If not in a block comment, the algorithm checks for the beginning of a block comment (`/*`) and sets the `in_block_comment` variable to `true`. If a line comment start (`//`) is found, it breaks the inner loop to skip the rest of the line since line comments end at the end of the line, making the rest of the line irrelevant. Otherwise, the algorithm appends the current character to the `buffer`.

After processing a line, if not in a block comment and the buffer is not empty, the content of the buffer is added to the result list, and the buffer is cleared.

Once all lines have been processed, the function returns the result list. The implementation remains mostly the same across all four languages, with slight variations due to the respective language syntax.

## A solution in Javascript

```javascript
var removeComments = function(source) {
    let result = [];
    let buffer = '';
    let inBlockComment = false;

    for (const line of source) {
        for (let i = 0; i < line.length; ++i) {
            if (inBlockComment) {
                if (i < line.length - 1 && line[i] === '*' && line[i + 1] === '/') {
                    inBlockComment = false;
                    ++i;
                }
            } else {
                if (i < line.length - 1 && line[i] === '/' && line[i + 1] === '*') {
                    inBlockComment = true;
                    ++i;
                } else if (i < line.length - 1 && line[i] === '/' && line[i + 1] === '/') {
                    break;
                } else {
                    buffer += line[i];
                }
            }
        }
        if (!inBlockComment && buffer.length) {
            result.push(buffer);
            buffer = '';
        }
    }
    return result;
};
```
The algorithm begins by initializing an empty result list, an empty buffer string or list, and a boolean variable `in_block_comment` set to `false`. Then, for each line in the source code, we iterate through the characters of the line. The algorithm checks if we are within a block comment or not. If so, it looks for the block comment end combination (`*/`) and sets `in_block_comment` to `false` if found, skipping the end combination characters.

If not in a block comment, the algorithm checks for the beginning of a block comment (`/*`) and sets the `in_block_comment` variable to `true`. If a line comment start (`//`) is found, it breaks the inner loop to skip the rest of the line since line comments end at the end of the line, making the rest of the line irrelevant. Otherwise, the algorithm appends the current character to the `buffer`.

After processing a line, if not in a block comment and the buffer is not empty, the content of the buffer is added to the result list, and the buffer is cleared.

Once all lines have been processed, the function returns the result list. The implementation remains mostly the same across all four languages, with slight variations due to the respective language syntax.


# Candy Crush

- slug: candy-crush
- difficulty: Medium

This question is about implementing a basic elimination algorithm for Candy Crush.

Given an `m x n` integer array `board` representing the grid of candy where `board[i][j]` represents the type of candy. A value of `board[i][j] == 0` represents that the cell is empty.

The given board represents the state of the game following the player's move. Now, you need to restore the board to a stable state by crushing candies according to the following rules:

*   If three or more candies of the same type are adjacent vertically or horizontally, crush them all at the same time - these positions become empty.
*   After crushing all candies simultaneously, if an empty space on the board has candies on top of itself, then these candies will drop until they hit a candy or bottom at the same time. No new candies will drop outside the top boundary.
*   After the above steps, there may exist more candies that can be crushed. If so, you need to repeat the above steps.
*   If there does not exist more candies that can be crushed (i.e., the board is stable), then return the current board.

You need to perform the above rules until the board becomes stable, then return _the stable board_.

**Example 1:**

**Input:** board = \[\[110,5,112,113,114\],\[210,211,5,213,214\],\[310,311,3,313,314\],\[410,411,412,5,414\],\[5,1,512,3,3\],\[610,4,1,613,614\],\[710,1,2,713,714\],\[810,1,2,1,1\],\[1,1,2,2,2\],\[4,1,4,4,1014\]\]
**Output:** \[\[0,0,0,0,0\],\[0,0,0,0,0\],\[0,0,0,0,0\],\[110,0,0,0,114\],\[210,0,0,0,214\],\[310,0,0,113,314\],\[410,0,0,213,414\],\[610,211,112,313,614\],\[710,311,412,613,714\],\[810,411,512,713,1014\]\]

**Example 2:**

**Input:** board = \[\[1,3,5,5,2\],\[3,4,3,3,1\],\[3,2,4,5,2\],\[2,4,4,5,5\],\[1,4,4,1,1\]\]
**Output:** \[\[1,3,0,0,0\],\[3,4,0,5,2\],\[3,2,0,3,1\],\[2,4,0,5,2\],\[1,4,3,1,1\]\]

**Constraints:**

*   `m == board.length`
*   `n == board[i].length`
*   `3 <= m, n <= 50`
*   `1 <= board[i][j] <= 2000`

## A solution in Java

```java
public int[][] candyCrush(int[][] board) {
    int rows = board.length, cols = board[0].length;
    boolean toDo = false;

    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols - 2; c++) {
            int val = Math.abs(board[r][c]);
            if (val != 0 && val == Math.abs(board[r][c + 1]) && val == Math.abs(board[r][c + 2])) {
                board[r][c] = board[r][c + 1] = board[r][c + 2] = -val;
                toDo = true;
            }
        }
    }

    for (int r = 0; r < rows - 2; r++) {
        for (int c = 0; c < cols; c++) {
            int val = Math.abs(board[r][c]);
            if (val != 0 && val == Math.abs(board[r + 1][c]) && val == Math.abs(board[r + 2][c])) {
                board[r][c] = board[r + 1][c] = board[r + 2][c] = -val;
                toDo = true;
            }
        }
    }

    for (int c = 0; c < cols; c++) {
        int wr = rows - 1;
        for (int r = rows - 1; r >= 0; r--)
            if (board[r][c] > 0)
                board[wr--][c] = board[r][c];
        while (wr >= 0)
            board[wr--][c] = 0;
    }

    return toDo ? candyCrush(board) : board;
}
```
The algorithm iterates over `board`, checking for matching candies both horizontally and vertically. If matching candies are found, their signs are inverted to mark them as crushed. After marking all matching candies, the empty cells are filled by dropping candies from above in the same column. Finally, the function is called recursively until no more matching candies are found.

## A solution in C++

```cpp
#include<vector>
using namespace std;
vector<vector<int>> candyCrush(vector<vector<int>>& board) {
    int rows = board.size(), cols = board[0].size();
    bool toDo = false;

    for (int r = 0; r < rows; r++) {
        for (int c = 0; c < cols - 2; c++) {
            int val = abs(board[r][c]);
            if (val && val == abs(board[r][c + 1]) && val == abs(board[r][c + 2])) {
                board[r][c] = board[r][c + 1] = board[r][c + 2] = -val;
                toDo = true;
            }
        }
    }

    for (int r = 0; r < rows - 2; r++) {
        for (int c = 0; c < cols; c++) {
            int val = abs(board[r][c]);
            if (val && val == abs(board[r + 1][c]) && val == abs(board[r + 2][c])) {
                board[r][c] = board[r + 1][c] = board[r + 2][c] = -val;
                toDo = true;
            }
        }
    }

    for (int c = 0; c < cols; c++) {
        int wr = rows - 1;
        for (int r = rows - 1; r >= 0; r--)
            if (board[r][c] > 0)
                board[wr--][c] = board[r][c];
        while (wr >= 0)
            board[wr--][c] = 0;
    }

    return toDo ? candyCrush(board) : board;
}
```
The algorithm iterates over `board`, checking for matching candies both horizontally and vertically. If matching candies are found, their signs are inverted to mark them as crushed. After marking all matching candies, the empty cells are filled by dropping candies from above in the same column. Finally, the function is called recursively until no more matching candies are found.

## A solution in Python

```python
def candyCrush(board):
    rows = len(board)
    cols = len(board[0])
    toDo = False

    for r in range(rows):
        for c in range(cols - 2):
            val = abs(board[r][c])
            if val and val == abs(board[r][c + 1]) and val == abs(board[r][c + 2]):
                board[r][c] = board[r][c + 1] = board[r][c + 2] = -val
                toDo = True

    for r in range(rows - 2):
        for c in range(cols):
            val = abs(board[r][c])
            if val and val == abs(board[r + 1][c]) and val == abs(board[r + 2][c]):
                board[r][c] = board[r + 1][c] = board[r + 2][c] = -val
                toDo = True

    for c in range(cols):
        wr = rows - 1
        for r in range(rows - 1, -1, -1):
            if board[r][c] > 0:
                board[wr][c] = board[r][c]
                wr -= 1

        for r in range(wr, -1, -1):
            board[r][c] = 0

    return candyCrush(board) if toDo else board
```
The algorithm iterates over `board`, checking for matching candies both horizontally and vertically. If matching candies are found, their signs are inverted to mark them as crushed. After marking all matching candies, the empty cells are filled by dropping candies from above in the same column. Finally, the function is called recursively until no more matching candies are found.

## A solution in Javascript

```javascript
function candyCrush(board) {
    let rows = board.length;
    let cols = board[0].length;
    let toDo = false;
    for (let r = 0; r < rows; r++) {
        for (let c = 0; c < cols - 2; c++) {
            let val = Math.abs(board[r][c]);
            if (val && val === Math.abs(board[r][c + 1]) && val === Math.abs(board[r][c + 2])) {
                board[r][c] = board[r][c + 1] = board[r][c + 2] = -val;
                toDo = true;
            }
        }
    }
    for (let r = 0; r < rows - 2; r++) {
        for (let c = 0; c < cols; c++) {
            let val = Math.abs(board[r][c]);
            if (val && val === Math.abs(board[r + 1][c]) && val === Math.abs(board[r + 2][c])) {
                board[r][c] = board[r + 1][c] = board[r + 2][c] = -val;
                toDo = true;
            }
        }
    }

    for (let c = 0; c < cols; c++) {
        let wr = rows - 1;
        for (let r = rows - 1; r >= 0; r--) {
            if (board[r][c] > 0) {
                board[wr][c] = board[r][c];
                wr--;
            }
        }
        for (let r = wr; r >= 0; r--) {
            board[r][c] = 0;
        }
    }

    return toDo ? candyCrush(board) : board;
}
```
The algorithm iterates over `board`, checking for matching candies both horizontally and vertically. If matching candies are found, their signs are inverted to mark them as crushed. After marking all matching candies, the empty cells are filled by dropping candies from above in the same column. Finally, the function is called recursively until no more matching candies are found.