# Distribute Candies to People

- slug: distribute-candies-to-people
- difficulty: Easy

We distribute some number of `candies`, to a row of **`n = num_people`** people in the following way:

We then give 1 candy to the first person, 2 candies to the second person, and so on until we give `n` candies to the last person.

Then, we go back to the start of the row, giving `n + 1` candies to the first person, `n + 2` candies to the second person, and so on until we give `2 * n` candies to the last person.

This process repeats (with us giving one more candy each time, and moving to the start of the row after we reach the end) until we run out of candies. The last person will receive all of our remaining candies (not necessarily one more than the previous gift).

Return an array (of length `num_people` and sum `candies`) that represents the final distribution of candies.

**Example 1:**

**Input:** candies = 7, num\_people = 4
**Output:** \[1,2,3,1\]
**Explanation:**
On the first turn, ans\[0\] += 1, and the array is \[1,0,0,0\].
On the second turn, ans\[1\] += 2, and the array is \[1,2,0,0\].
On the third turn, ans\[2\] += 3, and the array is \[1,2,3,0\].
On the fourth turn, ans\[3\] += 1 (because there is only one candy left), and the final array is \[1,2,3,1\].

**Example 2:**

**Input:** candies = 10, num\_people = 3
**Output:** \[5,2,3\]
**Explanation:**
On the first turn, ans\[0\] += 1, and the array is \[1,0,0\].
On the second turn, ans\[1\] += 2, and the array is \[1,2,0\].
On the third turn, ans\[2\] += 3, and the array is \[1,2,3\].
On the fourth turn, ans\[0\] += 4, and the final array is \[5,2,3\].

**Constraints:**

*   1 <= candies <= 10^9
*   1 <= num\_people <= 1000

## A solution in Java

```java
public int[] distributeCandies(int candies, int num_people) {
    int[] result = new int[num_people];
    int i = 0, count = 1;

    while (candies > 0) {
        result[i % num_people] += Math.min(candies, count);
        candies -= count;
        count++;
        i++;
    }

    return result;
}
```
The algorithm proceeds as follows:

1. Initialize an array `result` of length `num_people` with 0's.
2. Initialize two variables `i` and `count`, both with value 0. `i` will iterate through the people and `count` will store how many candies should be given at each step.
3. Loop until there are no more `candies` left.
    1. To distribute `candies` among people:
        - If the remaining `candies` are more than the current `count`, give `count` candies to the current person.
        - If the remaining `candies` are less than or equal to the current `count`, give the remaining `candies` to the current person and stop the loop.
    2. Update the remaining `candies` by subtracting the current `count`.
    3. Increment the current `count` and `i`.
4. After the loop, return the `result` array as the final distribution of candies.

## A solution in C++

```cpp
#include <vector>

std::vector<int> distributeCandies(int candies, int num_people) {
    std::vector<int> result(num_people, 0);
    int i = 0, count = 1;

    while (candies > 0) {
        result[i % num_people] += std::min(candies, count);
        candies -= count;
        count++;
        i++;
    }

    return result;
}
```
The algorithm proceeds as follows:

1. Initialize an array `result` of length `num_people` with 0's.
2. Initialize two variables `i` and `count`, both with value 0. `i` will iterate through the people and `count` will store how many candies should be given at each step.
3. Loop until there are no more `candies` left.
    1. To distribute `candies` among people:
        - If the remaining `candies` are more than the current `count`, give `count` candies to the current person.
        - If the remaining `candies` are less than or equal to the current `count`, give the remaining `candies` to the current person and stop the loop.
    2. Update the remaining `candies` by subtracting the current `count`.
    3. Increment the current `count` and `i`.
4. After the loop, return the `result` array as the final distribution of candies.

## A solution in Python

```python
def distribute_candies(candies, num_people):
    result = [0] * num_people
    i = 0
    count = 1

    while candies > 0:
        result[i % num_people] += min(candies, count)
        candies -= count
        count += 1
        i += 1

    return result
```
The algorithm proceeds as follows:

1. Initialize an array `result` of length `num_people` with 0's.
2. Initialize two variables `i` and `count`, both with value 0. `i` will iterate through the people and `count` will store how many candies should be given at each step.
3. Loop until there are no more `candies` left.
    1. To distribute `candies` among people:
        - If the remaining `candies` are more than the current `count`, give `count` candies to the current person.
        - If the remaining `candies` are less than or equal to the current `count`, give the remaining `candies` to the current person and stop the loop.
    2. Update the remaining `candies` by subtracting the current `count`.
    3. Increment the current `count` and `i`.
4. After the loop, return the `result` array as the final distribution of candies.

## A solution in Javascript

```javascript
function distributeCandies(candies, num_people) {
    const result = new Array(num_people).fill(0);
    let i = 0, count = 1;

    while (candies > 0) {
        result[i % num_people] += Math.min(candies, count);
        candies -= count;
        count++;
        i++;
    }

    return result;
}
```
The algorithm proceeds as follows:

1. Initialize an array `result` of length `num_people` with 0's.
2. Initialize two variables `i` and `count`, both with value 0. `i` will iterate through the people and `count` will store how many candies should be given at each step.
3. Loop until there are no more `candies` left.
    1. To distribute `candies` among people:
        - If the remaining `candies` are more than the current `count`, give `count` candies to the current person.
        - If the remaining `candies` are less than or equal to the current `count`, give the remaining `candies` to the current person and stop the loop.
    2. Update the remaining `candies` by subtracting the current `count`.
    3. Increment the current `count` and `i`.
4. After the loop, return the `result` array as the final distribution of candies.


# Path In Zigzag Labelled Binary Tree

- slug: path-in-zigzag-labelled-binary-tree
- difficulty: Medium

In an infinite binary tree where every node has two children, the nodes are labelled in row order.

In the odd numbered rows (ie., the first, third, fifth,...), the labelling is left to right, while in the even numbered rows (second, fourth, sixth,...), the labelling is right to left.

Given the `label` of a node in this tree, return the labels in the path from the root of the tree to the node with that `label`.

**Example 1:**

**Input:** label = 14
**Output:** \[1,3,4,14\]

**Example 2:**

**Input:** label = 26
**Output:** \[1,2,6,10,26\]

**Constraints:**

*   `1 <= label <= 10^6`

## A solution in Java

```java
public int[][] colorBorder(int[][] grid, int row, int col, int color) {
    int current = grid[row][col];
    if (current == color)
        return grid;

    dfs(grid, row, col, current, color + 1000);

    for (int i = 0; i < grid.length; i++) {
        for (int j = 0; j < grid[0].length; j++) {
            if (grid[i][j] > 1000)
                grid[i][j] -= 1000;
        }
    }

    return grid;
}

private void dfs(int[][] grid, int row, int col, int current, int color) {
    if (row < 0 || row >= grid.length || col < 0 || col >= grid[0].length || grid[row][col] != current)
        return;

    grid[row][col] = color;
    dfs(grid, row - 1, col, current, color);
    dfs(grid, row + 1, col, current, color);
    dfs(grid, row, col - 1, current, color);
    dfs(grid, row, col + 1, current, color);
}
```
This problem can be solved by using the Depth-First Search (DFS) algorithm. The key steps are as follows:
1. If the current color of the grid at the given `row` and `col` is the same as the `color` parameter, return the grid as is, since there's no need to change the border color.
2. Perform a DFS from the given grid cell with the `row` and `col` indices. During the DFS, update the cell's color with `color + 1000` to temporarily differentiate the border cells in the connected component. This temporary color will ensure we can revert it back to the original color if it is not a border cell.
3. After the DFS, iterate through the entire grid, and if a cell has a color value greater than `1000`, it means it was updated during the DFS. Subtract `1000` from its color value to get the final grid.

## A solution in C++

```cpp
#include <vector>

void dfs(std::vector<std::vector<int>>& grid, int row, int col, int current, int color) {
    if (row < 0 || row >= grid.size() || col < 0 || col >= grid[0].size() || grid[row][col] != current)
        return;

    grid[row][col] = color;
    dfs(grid, row+1, col, current, color);
    dfs(grid, row-1, col, current, color);
    dfs(grid, row, col+1, current, color);
    dfs(grid, row, col-1, current, color);
}

std::vector<std::vector<int>> colorBorder(std::vector<std::vector<int>>& grid, int row, int col, int color) {
    int current = grid[row][col];
    if (current == color)
        return grid;

    dfs(grid, row, col, current, color + 1000);

    for (int i = 0; i < grid.size(); ++i) {
        for (int j = 0; j < grid[0].size(); ++j) {
            if (grid[i][j] > 1000)
                grid[i][j] -= 1000;
        }
    }

    return grid;
}
```
This problem can be solved by using the Depth-First Search (DFS) algorithm. The key steps are as follows:
1. If the current color of the grid at the given `row` and `col` is the same as the `color` parameter, return the grid as is, since there's no need to change the border color.
2. Perform a DFS from the given grid cell with the `row` and `col` indices. During the DFS, update the cell's color with `color + 1000` to temporarily differentiate the border cells in the connected component. This temporary color will ensure we can revert it back to the original color if it is not a border cell.
3. After the DFS, iterate through the entire grid, and if a cell has a color value greater than `1000`, it means it was updated during the DFS. Subtract `1000` from its color value to get the final grid.

## A solution in Python

```python
def colorBorder(grid, row, col, color):
    def dfs(grid, row, col, current, color):
        if row < 0 or row >= len(grid) or col < 0 or col >= len(grid[0]) or grid[row][col] != current:
            return

        grid[row][col] = color
        dfs(grid, row - 1, col, current, color)
        dfs(grid, row + 1, col, current, color)
        dfs(grid, row, col - 1, current, color)
        dfs(grid, row, col + 1, current, color)

    current = grid[row][col]
    if current == color:
        return grid

    dfs(grid, row, col, current, color + 1000)

    for i in range(len(grid)):
        for j in range(len(grid[0])):
            if grid[i][j] > 1000:
                grid[i][j] -= 1000

    return grid
```
This problem can be solved by using the Depth-First Search (DFS) algorithm. The key steps are as follows:
1. If the current color of the grid at the given `row` and `col` is the same as the `color` parameter, return the grid as is, since there's no need to change the border color.
2. Perform a DFS from the given grid cell with the `row` and `col` indices. During the DFS, update the cell's color with `color + 1000` to temporarily differentiate the border cells in the connected component. This temporary color will ensure we can revert it back to the original color if it is not a border cell.
3. After the DFS, iterate through the entire grid, and if a cell has a color value greater than `1000`, it means it was updated during the DFS. Subtract `1000` from its color value to get the final grid.

## A solution in Javascript

```javascript
function colorBorder(grid, row, col, color) {
    function dfs(grid, row, col, current, color) {
        if (row < 0 || row >= grid.length || col < 0 || col >= grid[0].length || grid[row][col] !== current)
            return;

        grid[row][col] = color;
        dfs(grid, row - 1, col, current, color);
        dfs(grid, row + 1, col, current, color);
        dfs(grid, row, col - 1, current, color);
        dfs(grid, row, col + 1, current, color);
    }

    const current = grid[row][col];
    if (current === color)
        return grid;

    dfs(grid, row, col, current, color + 1000);

    for (let i = 0; i < grid.length; i++) {
        for (let j = 0; j < grid[0].length; j++) {
            if (grid[i][j] > 1000)
                grid[i][j] -= 1000;
        }
    }

    return grid;
}
```
This problem can be solved by using the Depth-First Search (DFS) algorithm. The key steps are as follows:
1. If the current color of the grid at the given `row` and `col` is the same as the `color` parameter, return the grid as is, since there's no need to change the border color.
2. Perform a DFS from the given grid cell with the `row` and `col` indices. During the DFS, update the cell's color with `color + 1000` to temporarily differentiate the border cells in the connected component. This temporary color will ensure we can revert it back to the original color if it is not a border cell.
3. After the DFS, iterate through the entire grid, and if a cell has a color value greater than `1000`, it means it was updated during the DFS. Subtract `1000` from its color value to get the final grid.


# Filling Bookcase Shelves

- slug: filling-bookcase-shelves
- difficulty: Medium

You are given an array `books` where `books[i] = [thicknessi, heighti]` indicates the thickness and height of the `ith` book. You are also given an integer `shelfWidth`.

We want to place these books in order onto bookcase shelves that have a total width `shelfWidth`.

We choose some of the books to place on this shelf such that the sum of their thickness is less than or equal to `shelfWidth`, then build another level of the shelf of the bookcase so that the total height of the bookcase has increased by the maximum height of the books we just put down. We repeat this process until there are no more books to place.

Note that at each step of the above process, the order of the books we place is the same order as the given sequence of books.

*   For example, if we have an ordered list of `5` books, we might place the first and second book onto the first shelf, the third book on the second shelf, and the fourth and fifth book on the last shelf.

Return _the minimum possible height that the total bookshelf can be after placing shelves in this manner_.

**Example 1:**

**Input:** books = \[\[1,1\],\[2,3\],\[2,3\],\[1,1\],\[1,1\],\[1,1\],\[1,2\]\], shelfWidth = 4
**Output:** 6
**Explanation:**
The sum of the heights of the 3 shelves is 1 + 3 + 2 = 6.
Notice that book number 2 does not have to be on the first shelf.

**Example 2:**

**Input:** books = \[\[1,3\],\[2,4\],\[3,2\]\], shelfWidth = 6
**Output:** 4

**Constraints:**

*   `1 <= books.length <= 1000`
*   `1 <= thicknessi <= shelfWidth <= 1000`
*   `1 <= heighti <= 1000`

## A solution in Java

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

    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (nums1[i - 1] == nums2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[m][n];
}
```
The problem can be solved using dynamic programming. We create a dp matrix (m+1)x(n+1) where m and n are the lengths of nums1 and nums2 respectively. The value dp[i][j] will store the maximum number of connecting lines between the first i numbers in nums1 and the first j numbers in nums2.

We iterate through the dp matrix, and if nums1[i-1] is equal to nums2[j-1], we get a new connecting line, and the value will be dp[i-1][j-1] + 1. If the numbers are not equal, we pick the maximum value from the left or the upper cell (dp[i-1][j] and dp[i][j-1]) because either we pick a number from nums1 or nums2 but not both.

The result will be stored in dp[m][n], which will give us the maximum number of connecting lines for the complete nums1 and nums2 arrays.

## A solution in C++

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

int maxUncrossedLines(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));

    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            if (nums1[i - 1] == nums2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[m][n];
}
```
The problem can be solved using dynamic programming. We create a dp matrix (m+1)x(n+1) where m and n are the lengths of nums1 and nums2 respectively. The value dp[i][j] will store the maximum number of connecting lines between the first i numbers in nums1 and the first j numbers in nums2.

We iterate through the dp matrix, and if nums1[i-1] is equal to nums2[j-1], we get a new connecting line, and the value will be dp[i-1][j-1] + 1. If the numbers are not equal, we pick the maximum value from the left or the upper cell (dp[i-1][j] and dp[i][j-1]) because either we pick a number from nums1 or nums2 but not both.

The result will be stored in dp[m][n], which will give us the maximum number of connecting lines for the complete nums1 and nums2 arrays.

## A solution in Python

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

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

    return dp[m][n]
```
The problem can be solved using dynamic programming. We create a dp matrix (m+1)x(n+1) where m and n are the lengths of nums1 and nums2 respectively. The value dp[i][j] will store the maximum number of connecting lines between the first i numbers in nums1 and the first j numbers in nums2.

We iterate through the dp matrix, and if nums1[i-1] is equal to nums2[j-1], we get a new connecting line, and the value will be dp[i-1][j-1] + 1. If the numbers are not equal, we pick the maximum value from the left or the upper cell (dp[i-1][j] and dp[i][j-1]) because either we pick a number from nums1 or nums2 but not both.

The result will be stored in dp[m][n], which will give us the maximum number of connecting lines for the complete nums1 and nums2 arrays.

## A solution in Javascript

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

    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            if (nums1[i - 1] === nums2[j - 1]) {
                dp[i][j] = dp[i - 1][j - 1] + 1;
            } else {
                dp[i][j] = Math.max(dp[i - 1][j], dp[i][j - 1]);
            }
        }
    }
    return dp[m][n];
}
```
The problem can be solved using dynamic programming. We create a dp matrix (m+1)x(n+1) where m and n are the lengths of nums1 and nums2 respectively. The value dp[i][j] will store the maximum number of connecting lines between the first i numbers in nums1 and the first j numbers in nums2.

We iterate through the dp matrix, and if nums1[i-1] is equal to nums2[j-1], we get a new connecting line, and the value will be dp[i-1][j-1] + 1. If the numbers are not equal, we pick the maximum value from the left or the upper cell (dp[i-1][j] and dp[i][j-1]) because either we pick a number from nums1 or nums2 but not both.

The result will be stored in dp[m][n], which will give us the maximum number of connecting lines for the complete nums1 and nums2 arrays.


# Parsing A Boolean Expression

- slug: parsing-a-boolean-expression
- difficulty: Hard

A **boolean expression** is an expression that evaluates to either `true` or `false`. It can be in one of the following shapes:

*   `'t'` that evaluates to `true`.
*   `'f'` that evaluates to `false`.
*   `'!(subExpr)'` that evaluates to **the logical NOT** of the inner expression `subExpr`.
*   `'&(subExpr1, subExpr2, ..., subExprn)'` that evaluates to **the logical AND** of the inner expressions `subExpr1, subExpr2, ..., subExprn` where `n >= 1`.
*   `'|(subExpr1, subExpr2, ..., subExprn)'` that evaluates to **the logical OR** of the inner expressions `subExpr1, subExpr2, ..., subExprn` where `n >= 1`.

Given a string `expression` that represents a **boolean expression**, return _the evaluation of that expression_.

It is **guaranteed** that the given expression is valid and follows the given rules.

**Example 1:**

**Input:** expression =  "&(|(f)) "
**Output:** false
**Explanation:**
First, evaluate |(f) --> f. The expression is now  "&(f) ".
Then, evaluate &(f) --> f. The expression is now  "f ".
Finally, return false.

**Example 2:**

**Input:** expression =  "|(f,f,f,t) "
**Output:** true
**Explanation:** The evaluation of (false OR false OR false OR true) is true.

**Example 3:**

**Input:** expression =  "!(&(f,t)) "
**Output:** true
**Explanation:**
First, evaluate &(f,t) --> (false AND true) --> false --> f. The expression is now  "!(f) ".
Then, evaluate !(f) --> NOT false --> true. We return true.

**Constraints:**

*   `1 <= expression.length <= 2 * 104`
*   expression\[i\] is one following characters: `'('`, `')'`, `'&'`, `'|'`, `'!'`, `'t'`, `'f'`, and `','`.

## A solution in Java

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

public boolean isEscapePossible(List<List<Integer>> blocked, List<Integer> source, List<Integer> target) {
    Set<String> blockedSet = new HashSet<>();
    Set<String> visited = new HashSet<>();
    int maxSteps = 200;

    for (List<Integer> block : blocked)
        blockedSet.add(block.get(0) + "_" + block.get(1));

    return dfs(source.get(0), source.get(1), target.get(0), target.get(1), blockedSet, visited, 0, maxSteps);
}

private boolean dfs(int x, int y, int tx, int ty, Set<String> blocked, Set<String> visited, int steps, int maxSteps) {
    String pos = x + "_" + y;
    if (x < 0 || x >= 1000000 || y < 0 || y >= 1000000 || steps >= maxSteps || blocked.contains(pos) || visited.contains(pos)) {
        return false;
    }

    if (x == tx && y == ty) {
        return true;
    }

    visited.add(pos);

    return dfs(x + 1, y, tx, ty, blocked, visited, steps + 1, maxSteps) ||
           dfs(x, y + 1, tx, ty, blocked, visited, steps + 1, maxSteps) ||
           dfs(x - 1, y, tx, ty, blocked, visited, steps + 1, maxSteps) ||
           dfs(x, y - 1, tx, ty, blocked, visited, steps + 1, maxSteps);
}
```
We can use DFS (Depth First Search) to solve this problem. The limitation of a maximum of 1 million by 1 million grid is to limit the search space, while the 200-move limit prevents the DFS search from running excessively long. The key is to have a `blockedSet` to store the blocked positions and a `visited` set to keep track of visited positions.

We will implement a helper function named `dfs` with the current position `(x, y)`, target position `(tx, ty)`, the `blockedSet`, the `visited` set, and the current step count.

At each step, we first check if the current position is valid (inside the grid, not blocked, not visited, and the step count below 200), if not, return false. If the current position is the target position, return true. Otherwise, we mark the current position as visited and call the `dfs` function in all four directions (North, South, East, West) and return true if any of them return true.

Finally, we call our `dfs` function with the source position as the starting point and return the result.

Using this algorithm, we can achieve the result without exceeding the provided limitations.

## A solution in C++

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

const int MAX_STEPS = 200;

bool dfs(int x, int y, int tx, int ty, std::unordered_set<std::string> &blocked, std::unordered_set<std::string> &visited, int steps) {
    std::string pos = std::to_string(x) + "_" + std::to_string(y);
    if (x < 0 || x >= 1000000 || y < 0 || y >= 1000000 || steps >= MAX_STEPS || blocked.count(pos) || visited.count(pos))
        return false;

    if (x == tx && y == ty)
        return true;

    visited.insert(pos);

    if (dfs(x + 1, y, tx, ty, blocked, visited, steps + 1) || dfs(x, y + 1, tx, ty, blocked, visited, steps + 1) ||
        dfs(x - 1, y, tx, ty, blocked, visited, steps + 1) || dfs(x, y - 1, tx, ty, blocked, visited, steps + 1))
        return true;

    return false;
}

bool isEscapePossible(std::vector<std::vector<int>>& blocked, std::vector<int>& source, std::vector<int>& target) {
    std::unordered_set<std::string> blockedSet, visited;
    for (auto &block : blocked)
        blockedSet.insert(std::to_string(block[0]) + "_" + std::to_string(block[1]));

    return dfs(source[0], source[1], target[0], target[1], blockedSet, visited, 0);
}
```
We can use DFS (Depth First Search) to solve this problem. The limitation of a maximum of 1 million by 1 million grid is to limit the search space, while the 200-move limit prevents the DFS search from running excessively long. The key is to have a `blockedSet` to store the blocked positions and a `visited` set to keep track of visited positions.

We will implement a helper function named `dfs` with the current position `(x, y)`, target position `(tx, ty)`, the `blockedSet`, the `visited` set, and the current step count.

At each step, we first check if the current position is valid (inside the grid, not blocked, not visited, and the step count below 200), if not, return false. If the current position is the target position, return true. Otherwise, we mark the current position as visited and call the `dfs` function in all four directions (North, South, East, West) and return true if any of them return true.

Finally, we call our `dfs` function with the source position as the starting point and return the result.

Using this algorithm, we can achieve the result without exceeding the provided limitations.

## A solution in Python

```python
MAX_STEPS = 200

def isEscapePossible(blocked, source, target):
    blockedSet = set(["{}_{}".format(block[0], block[1]) for block in blocked])
    visited = set()

    def dfs(x, y, tx, ty, steps):
        pos = "{}_{}".format(x, y)
        if x < 0 or x >= 1000000 or y < 0 or y >= 1000000 or steps >= MAX_STEPS or pos in blockedSet or pos in visited:
            return False

        if x == tx and y == ty:
            return True

        visited.add(pos)

        return (dfs(x + 1, y, tx, ty, steps + 1) or dfs(x, y + 1, tx, ty, steps + 1)
                or dfs(x - 1, y, tx, ty, steps + 1) or dfs(x, y - 1, tx, ty, steps + 1))

    return dfs(source[0], source[1], target[0], target[1], 0)
```
We can use DFS (Depth First Search) to solve this problem. The limitation of a maximum of 1 million by 1 million grid is to limit the search space, while the 200-move limit prevents the DFS search from running excessively long. The key is to have a `blockedSet` to store the blocked positions and a `visited` set to keep track of visited positions.

We will implement a helper function named `dfs` with the current position `(x, y)`, target position `(tx, ty)`, the `blockedSet`, the `visited` set, and the current step count.

At each step, we first check if the current position is valid (inside the grid, not blocked, not visited, and the step count below 200), if not, return false. If the current position is the target position, return true. Otherwise, we mark the current position as visited and call the `dfs` function in all four directions (North, South, East, West) and return true if any of them return true.

Finally, we call our `dfs` function with the source position as the starting point and return the result.

Using this algorithm, we can achieve the result without exceeding the provided limitations.

## A solution in Javascript

```javascript
const MAX_STEPS = 200;

function isEscapePossible(blocked, source, target) {
    const blockedSet = new Set(blocked.map(block => `${block[0]}_${block[1]}`));
    const visited = new Set();

    function dfs(x, y, tx, ty, steps) {
        const pos = `${x}_${y}`;
        if (x < 0 || x >= 1000000 || y < 0 || y >= 1000000 || steps >= MAX_STEPS || blockedSet.has(pos) || visited.has(pos)) {
            return false;
        }

        if (x === tx && y === ty) {
            return true;
        }

        visited.add(pos);

        return dfs(x + 1, y, tx, ty, steps + 1) || dfs(x, y + 1, tx, ty, steps + 1) ||
               dfs(x - 1, y, tx, ty, steps + 1) || dfs(x, y - 1, tx, ty, steps + 1);
    }

    return dfs(source[0], source[1], target[0], target[1], 0);
}
```
We can use DFS (Depth First Search) to solve this problem. The limitation of a maximum of 1 million by 1 million grid is to limit the search space, while the 200-move limit prevents the DFS search from running excessively long. The key is to have a `blockedSet` to store the blocked positions and a `visited` set to keep track of visited positions.

We will implement a helper function named `dfs` with the current position `(x, y)`, target position `(tx, ty)`, the `blockedSet`, the `visited` set, and the current step count.

At each step, we first check if the current position is valid (inside the grid, not blocked, not visited, and the step count below 200), if not, return false. If the current position is the target position, return true. Otherwise, we mark the current position as visited and call the `dfs` function in all four directions (North, South, East, West) and return true if any of them return true.

Finally, we call our `dfs` function with the source position as the starting point and return the result.

Using this algorithm, we can achieve the result without exceeding the provided limitations.


# Defanging an IP Address

- slug: defanging-an-ip-address
- difficulty: Easy

Given a valid (IPv4) IP `address`, return a defanged version of that IP address.

A _defanged IP address_ replaces every period `". "` with `"[.] "`.

**Example 1:**

**Input:** address = "1.1.1.1"
**Output:** "1\[.\]1\[.\]1\[.\]1"

**Example 2:**

**Input:** address = "255.100.50.0"
**Output:** "255\[.\]100\[.\]50\[.\]0"

**Constraints:**

*   The given `address` is a valid IPv4 address.

## A solution in Java

```java
public String defangIPaddr(String address) {
    StringBuilder defanged = new StringBuilder();
    for (char c : address.toCharArray()) {
        if (c == '.')
            defanged.append("[.]");
        else
            defanged.append(c);
    }
    return defanged.toString();
}
```
The function for each language takes an input address, which is a valid IPv4 address. It iterates through each character of the string, checking for a period ('.'). If a period is found, we replace it with "[.]" in the resulting string. For other characters, we just add them to the resulting string.

In C++, Java, and JavaScript, we iterate over each character using a for loop, appending the processed character to a string object or a StringBuilder object. Java uses a StringBuilder object for more efficient string concatenation.

In Python, we can directly use the string method `replace()` to replace all occurrences of the period with "[.]" in a more concise way.

At the end of the function, we return the defanged IP address as string.

## A solution in C++

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

string defangIPaddr(string address) {
    string defanged = "";
    for (char c : address) {
        if (c == '.')
            defanged += "[.]";
        else
            defanged += c;
    }
    return defanged;
}
```
The function for each language takes an input address, which is a valid IPv4 address. It iterates through each character of the string, checking for a period ('.'). If a period is found, we replace it with "[.]" in the resulting string. For other characters, we just add them to the resulting string.

In C++, Java, and JavaScript, we iterate over each character using a for loop, appending the processed character to a string object or a StringBuilder object. Java uses a StringBuilder object for more efficient string concatenation.

In Python, we can directly use the string method `replace()` to replace all occurrences of the period with "[.]" in a more concise way.

At the end of the function, we return the defanged IP address as string.

## A solution in Python

```python
def defangIPaddr(address: str) -> str:
    return address.replace('.', '[.]')
```
The function for each language takes an input address, which is a valid IPv4 address. It iterates through each character of the string, checking for a period ('.'). If a period is found, we replace it with "[.]" in the resulting string. For other characters, we just add them to the resulting string.

In C++, Java, and JavaScript, we iterate over each character using a for loop, appending the processed character to a string object or a StringBuilder object. Java uses a StringBuilder object for more efficient string concatenation.

In Python, we can directly use the string method `replace()` to replace all occurrences of the period with "[.]" in a more concise way.

At the end of the function, we return the defanged IP address as string.

## A solution in Javascript

```javascript
function defangIPaddr(address) {
    return address.split('.').join('[.]');
}
```
The function for each language takes an input address, which is a valid IPv4 address. It iterates through each character of the string, checking for a period ('.'). If a period is found, we replace it with "[.]" in the resulting string. For other characters, we just add them to the resulting string.

In C++, Java, and JavaScript, we iterate over each character using a for loop, appending the processed character to a string object or a StringBuilder object. Java uses a StringBuilder object for more efficient string concatenation.

In Python, we can directly use the string method `replace()` to replace all occurrences of the period with "[.]" in a more concise way.

At the end of the function, we return the defanged IP address as string.


# Corporate Flight Bookings

- slug: corporate-flight-bookings
- difficulty: Medium

There are `n` flights that are labeled from `1` to `n`.

You are given an array of flight bookings `bookings`, where `bookings[i] = [firsti, lasti, seatsi]` represents a booking for flights `firsti` through `lasti` (**inclusive**) with `seatsi` seats reserved for **each flight** in the range.

Return _an array_ `answer` _of length_ `n`_, where_ `answer[i]` _is the total number of seats reserved for flight_ `i`.

**Example 1:**

**Input:** bookings = \[\[1,2,10\],\[2,3,20\],\[2,5,25\]\], n = 5
**Output:** \[10,55,45,25,25\]
**Explanation:**
Flight labels:        1   2   3   4   5
Booking 1 reserved:  10  10
Booking 2 reserved:      20  20
Booking 3 reserved:      25  25  25  25
Total seats:         10  55  45  25  25
Hence, answer = \[10,55,45,25,25\]

**Example 2:**

**Input:** bookings = \[\[1,2,10\],\[2,2,15\]\], n = 2
**Output:** \[10,25\]
**Explanation:**
Flight labels:        1   2
Booking 1 reserved:  10  10
Booking 2 reserved:      15
Total seats:         10  25
Hence, answer = \[10,25\]

**Constraints:**

*   `1 <= n <= 2 * 104`
*   `1 <= bookings.length <= 2 * 104`
*   `bookings[i].length == 3`
*   `1 <= firsti <= lasti <= n`
*   `1 <= seatsi <= 104`

## A solution in Java

```java
public int[] corpFlightBookings(int[][] bookings, int n) {
    int[] seats = new int[n];
    for (int[] booking : bookings) {
        seats[booking[0] - 1] += booking[2];
        if (booking[1] < n) {
            seats[booking[1]] -= booking[2];
        }
    }
    for (int i = 1; i < n; ++i) {
        seats[i] += seats[i - 1];
    }
    return seats;
}
```
The algorithm initializes an array of `n` elements with all elements set to `0`. Then it iterates through the `bookings` array and for each booking, it adds the `seats` at the position `first_i - 1` and subtracts the `seats` at `last_i` if `last_i` is within the range of the array. This process gives us an initial array representing the change in seats for each flight. Finally, it iterates through the array adjusting the count for each flight by summing the previous flight count to get the total count. This gives the desired output with a time complexity of `O(n)` where `n` is the number of flights.

## A solution in C++

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

vector<int> corpFlightBookings(vector<vector<int>>& bookings, int n) {
    vector<int> seats(n, 0);
    for (auto& booking : bookings) {
        seats[booking[0] - 1] += booking[2];
        if (booking[1] < n) {
            seats[booking[1]] -= booking[2];
        }
    }
    for (int i = 1; i < n; ++i) {
        seats[i] += seats[i - 1];
    }
    return seats;
}
```
The algorithm initializes an array of `n` elements with all elements set to `0`. Then it iterates through the `bookings` array and for each booking, it adds the `seats` at the position `first_i - 1` and subtracts the `seats` at `last_i` if `last_i` is within the range of the array. This process gives us an initial array representing the change in seats for each flight. Finally, it iterates through the array adjusting the count for each flight by summing the previous flight count to get the total count. This gives the desired output with a time complexity of `O(n)` where `n` is the number of flights.

## A solution in Python

```python
def corpFlightBookings(bookings, n):
    seats = [0] * n
    for booking in bookings:
        seats[booking[0] - 1] += booking[2]
        if booking[1] < n:
            seats[booking[1]] -= booking[2]
    for i in range(1, n):
        seats[i] += seats[i - 1]
    return seats
```
The algorithm initializes an array of `n` elements with all elements set to `0`. Then it iterates through the `bookings` array and for each booking, it adds the `seats` at the position `first_i - 1` and subtracts the `seats` at `last_i` if `last_i` is within the range of the array. This process gives us an initial array representing the change in seats for each flight. Finally, it iterates through the array adjusting the count for each flight by summing the previous flight count to get the total count. This gives the desired output with a time complexity of `O(n)` where `n` is the number of flights.

## A solution in Javascript

```javascript
function corpFlightBookings(bookings, n) {
    const seats = new Array(n).fill(0);
    for (const booking of bookings) {
        seats[booking[0] - 1] += booking[2];
        if (booking[1] < n) {
            seats[booking[1]] -= booking[2];
        }
    }
    for (let i = 1; i < n; ++i) {
        seats[i] += seats[i - 1];
    }
    return seats;
}
```
The algorithm initializes an array of `n` elements with all elements set to `0`. Then it iterates through the `bookings` array and for each booking, it adds the `seats` at the position `first_i - 1` and subtracts the `seats` at `last_i` if `last_i` is within the range of the array. This process gives us an initial array representing the change in seats for each flight. Finally, it iterates through the array adjusting the count for each flight by summing the previous flight count to get the total count. This gives the desired output with a time complexity of `O(n)` where `n` is the number of flights.


# Delete Nodes And Return Forest

- slug: delete-nodes-and-return-forest
- difficulty: Medium

Given the `root` of a binary tree, each node in the tree has a distinct value.

After deleting all nodes with a value in `to_delete`, we are left with a forest (a disjoint union of trees).

Return the roots of the trees in the remaining forest. You may return the result in any order.

**Example 1:**

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

**Example 2:**

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

**Constraints:**

*   The number of nodes in the given tree is at most `1000`.
*   Each node has a distinct value between `1` and `1000`.
*   `to_delete.length <= 1000`
*   `to_delete` contains distinct values between `1` and `1000`.

## A solution in Java

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

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

public List<TreeNode> delNodes(TreeNode root, int[] to_delete) {
    Set<Integer> to_delete_set = new HashSet<>();
    for (int i : to_delete) to_delete_set.add(i);
    List<TreeNode> remaining_trees = new ArrayList<>();

    TreeNode removeNodes(TreeNode node) {
        if (node == null) return null;
        node.left = removeNodes(node.left);
        node.right = removeNodes(node.right);
        if (to_delete_set.contains(node.val)) {
            if (node.left != null) remaining_trees.add(node.left);
            if (node.right != null) remaining_trees.add(node.right);
            return null;
        }
        return node;
    }

    if (removeNodes(root) != null) remaining_trees.add(root);
    return remaining_trees;
}
```
The algorithm uses recursion to solve the problem. The algorithm can be divided into the following steps:

1. Create a helper method named `removeNodes`, which takes a tree node as a parameter and returns the node itself (a tree) after deleting nodes in to_delete list.
- Use a set for `to_delete` values for efficient lookups.
2. Use a recursive strategy for the helper method:
   - If it reaches a null node, simply return null.
   - Recursively call the method for the left and right children of the node.
   - If the node's value is in the `to_delete_set`:
       - Add the left child to the `remaining_trees` list if it is not null.
       - Add the right child to the `remaining_trees` list if it is not null.
       - Return null.
   - Otherwise, return the node itself.
3. Call the helper method for the root node and add it to the remaining_trees list if it is not null.
4. Return the list of remaining_trees.

Overall, the algorithm's time complexity is O(n) where n is the number of nodes in the tree. This is because it traverses each node in the tree once.

## A solution in C++

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

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

vector<TreeNode*> delNodes(TreeNode* root, vector<int>& to_delete) {
    set<int> to_delete_set(to_delete.begin(), to_delete.end());
    vector<TreeNode*> remaining_trees;

    function<TreeNode*(TreeNode*)> removeNodes = [&](TreeNode* node) -> TreeNode* {
        if (node == nullptr) return nullptr;
        node->left = removeNodes(node->left);
        node->right = removeNodes(node->right);
        if (to_delete_set.count(node->val)) {
            if (node->left) remaining_trees.push_back(node->left);
            if (node->right) remaining_trees.push_back(node->right);
            return nullptr;
        }
        return node;
    };

    if (removeNodes(root)) remaining_trees.push_back(root);
    return remaining_trees;
}
```
The algorithm uses recursion to solve the problem. The algorithm can be divided into the following steps:

1. Create a helper method named `removeNodes`, which takes a tree node as a parameter and returns the node itself (a tree) after deleting nodes in to_delete list.
- Use a set for `to_delete` values for efficient lookups.
2. Use a recursive strategy for the helper method:
   - If it reaches a null node, simply return null.
   - Recursively call the method for the left and right children of the node.
   - If the node's value is in the `to_delete_set`:
       - Add the left child to the `remaining_trees` list if it is not null.
       - Add the right child to the `remaining_trees` list if it is not null.
       - Return null.
   - Otherwise, return the node itself.
3. Call the helper method for the root node and add it to the remaining_trees list if it is not null.
4. Return the list of remaining_trees.

Overall, the algorithm's time complexity is O(n) where n is the number of nodes in the tree. This is because it traverses each node in the tree once.

## A solution in Python

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

def delNodes(root: TreeNode, to_delete):
    to_delete_set = set(to_delete)
    remaining_trees = []

    def removeNodes(node):
        if node is None:
            return None
        node.left = removeNodes(node.left)
        node.right = removeNodes(node.right)
        if node.val in to_delete_set:
            if node.left:
                remaining_trees.append(node.left)
            if node.right:
                remaining_trees.append(node.right)
            return None
        return node

    if removeNodes(root):
        remaining_trees.append(root)
    return remaining_trees
```
The algorithm uses recursion to solve the problem. The algorithm can be divided into the following steps:

1. Create a helper method named `removeNodes`, which takes a tree node as a parameter and returns the node itself (a tree) after deleting nodes in to_delete list.
- Use a set for `to_delete` values for efficient lookups.
2. Use a recursive strategy for the helper method:
   - If it reaches a null node, simply return null.
   - Recursively call the method for the left and right children of the node.
   - If the node's value is in the `to_delete_set`:
       - Add the left child to the `remaining_trees` list if it is not null.
       - Add the right child to the `remaining_trees` list if it is not null.
       - Return null.
   - Otherwise, return the node itself.
3. Call the helper method for the root node and add it to the remaining_trees list if it is not null.
4. Return the list of remaining_trees.

Overall, the algorithm's time complexity is O(n) where n is the number of nodes in the tree. This is because it traverses each node in the tree once.

## A solution in Javascript

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

function delNodes(root, to_delete) {
    const to_delete_set = new Set(to_delete);
    const remaining_trees = [];

    function removeNodes(node) {
        if (node === null) return null;
        node.left = removeNodes(node.left);
        node.right = removeNodes(node.right);
        if (to_delete_set.has(node.val)) {
            if (node.left) remaining_trees.push(node.left);
            if (node.right) remaining_trees.push(node.right);
            return null;
        }
        return node;
    }

    if (removeNodes(root)) remaining_trees.push(root);
    return remaining_trees;
}
```
The algorithm uses recursion to solve the problem. The algorithm can be divided into the following steps:

1. Create a helper method named `removeNodes`, which takes a tree node as a parameter and returns the node itself (a tree) after deleting nodes in to_delete list.
- Use a set for `to_delete` values for efficient lookups.
2. Use a recursive strategy for the helper method:
   - If it reaches a null node, simply return null.
   - Recursively call the method for the left and right children of the node.
   - If the node's value is in the `to_delete_set`:
       - Add the left child to the `remaining_trees` list if it is not null.
       - Add the right child to the `remaining_trees` list if it is not null.
       - Return null.
   - Otherwise, return the node itself.
3. Call the helper method for the root node and add it to the remaining_trees list if it is not null.
4. Return the list of remaining_trees.

Overall, the algorithm's time complexity is O(n) where n is the number of nodes in the tree. This is because it traverses each node in the tree once.


# Maximum Nesting Depth of Two Valid Parentheses Strings

- slug: maximum-nesting-depth-of-two-valid-parentheses-strings
- difficulty: Medium

A string is a _valid parentheses string_ (denoted VPS) if and only if it consists of `"( "` and `") "` characters only, and:

*   It is the empty string, or
*   It can be written as `AB` (`A` concatenated with `B`), where `A` and `B` are VPS's, or
*   It can be written as `(A)`, where `A` is a VPS.

We can similarly define the _nesting depth_ `depth(S)` of any VPS `S` as follows:

*   `depth( " ") = 0`
*   `depth(A + B) = max(depth(A), depth(B))`, where `A` and `B` are VPS's
*   `depth( "( " + A + ") ") = 1 + depth(A)`, where `A` is a VPS.

For example, `" "`, `"()() "`, and `"()(()()) "` are VPS's (with nesting depths 0, 1, and 2), and `")( "` and `"(() "` are not VPS's.

Given a VPS seq, split it into two disjoint subsequences `A` and `B`, such that `A` and `B` are VPS's (and `A.length + B.length = seq.length`).

Now choose **any** such `A` and `B` such that `max(depth(A), depth(B))` is the minimum possible value.

Return an `answer` array (of length `seq.length`) that encodes such a choice of `A` and `B`: `answer[i] = 0` if `seq[i]` is part of `A`, else `answer[i] = 1`. Note that even though multiple answers may exist, you may return any of them.

**Example 1:**

**Input:** seq =  "(()()) "
**Output:** \[0,1,1,1,1,0\]

**Example 2:**

**Input:** seq =  "()(())() "
**Output:** \[0,0,0,1,1,0,1,1\]

**Constraints:**

*   `1 <= seq.size <= 10000`

## A solution in Java

```java
public int minScoreTriangulation(int[] values) {
    int n = values.length;
    int[][] dp = new int[n][n];

    for (int len = 3; len <= n; ++len) {
        for (int i = 0; i + len - 1 < n; ++i) {
            int j = i + len - 1;
            dp[i][j] = Integer.MAX_VALUE;
            for (int k = i + 1; k < j; ++k) {
                dp[i][j] = Math.min(dp[i][j], values[i] * values[j] * values[k] + dp[i][k] + dp[k][j]);
            }
        }
    }

    return dp[0][n - 1];
}
```
First, initialize an `n` by `n` array (2D array) `dp` where `dp[i][j]` represents the minimum score/weight for the triangulation of the vertices from `i` to `j` (inclusive). The base case is when `dp[i][j]` is an edge in the polygon, in which case the weight is 0 since there is no triangle formed between those vertices.

Now, iterate through all possible lengths of the polygon from 3 to `n`. For each length, iterate through all possible vertex pairs (`i`, `j`) with the given length between them, and for each vertex `k` between `i` and `j`, consider the minimum possible weights with the current triangle formed by vertices (`i`, `j`, `k`). The weight of the considered triangles is calculated by taking the product of values at vertices `i`, `j`, and `k`, then add the weights for the other two triangles.

Finally, return the minimum score/weight `dp[0][n - 1]` which represents the triangulation of the whole polygon.

## A solution in C++

```cpp
int minScoreTriangulation(vector<int>& values) {
    int n = values.size();
    vector<vector<int>> dp(n, vector<int>(n, 0));

    for (int len = 3; len <= n; ++len) {
        for (int i = 0; i + len - 1 < n; ++i) {
            int j = i + len - 1;
            dp[i][j] = INT_MAX;
            for (int k = i + 1; k < j; ++k) {
                dp[i][j] = min(dp[i][j], values[i] * values[j] * values[k] + dp[i][k] + dp[k][j]);
            }
        }
    }

    return dp[0][n - 1];
}
```
First, initialize an `n` by `n` array (2D array) `dp` where `dp[i][j]` represents the minimum score/weight for the triangulation of the vertices from `i` to `j` (inclusive). The base case is when `dp[i][j]` is an edge in the polygon, in which case the weight is 0 since there is no triangle formed between those vertices.

Now, iterate through all possible lengths of the polygon from 3 to `n`. For each length, iterate through all possible vertex pairs (`i`, `j`) with the given length between them, and for each vertex `k` between `i` and `j`, consider the minimum possible weights with the current triangle formed by vertices (`i`, `j`, `k`). The weight of the considered triangles is calculated by taking the product of values at vertices `i`, `j`, and `k`, then add the weights for the other two triangles.

Finally, return the minimum score/weight `dp[0][n - 1]` which represents the triangulation of the whole polygon.

## A solution in Python

```python
def minScoreTriangulation(values):
    n = len(values)
    dp = [[0] * n for _ in range(n)]

    for length in range(3, n + 1):
        for i in range(n - length + 1):
            j = i + length - 1
            dp[i][j] = float('inf')
            for k in range(i + 1, j):
                dp[i][j] = min(dp[i][j], values[i] * values[j] * values[k] + dp[i][k] + dp[k][j])

    return dp[0][n - 1]
```
First, initialize an `n` by `n` array (2D array) `dp` where `dp[i][j]` represents the minimum score/weight for the triangulation of the vertices from `i` to `j` (inclusive). The base case is when `dp[i][j]` is an edge in the polygon, in which case the weight is 0 since there is no triangle formed between those vertices.

Now, iterate through all possible lengths of the polygon from 3 to `n`. For each length, iterate through all possible vertex pairs (`i`, `j`) with the given length between them, and for each vertex `k` between `i` and `j`, consider the minimum possible weights with the current triangle formed by vertices (`i`, `j`, `k`). The weight of the considered triangles is calculated by taking the product of values at vertices `i`, `j`, and `k`, then add the weights for the other two triangles.

Finally, return the minimum score/weight `dp[0][n - 1]` which represents the triangulation of the whole polygon.

## A solution in Javascript

```javascript
function minScoreTriangulation(values) {
    const n = values.length;
    const dp = Array.from({ length: n }, () => Array(n).fill(0));

    for (let len = 3; len <= n; ++len) {
        for (let i = 0; i + len - 1 < n; ++i) {
            const j = i + len - 1;
            dp[i][j] = Infinity;
            for (let k = i + 1; k < j; ++k) {
                dp[i][j] = Math.min(dp[i][j], values[i] * values[j] * values[k] + dp[i][k] + dp[k][j]);
            }
        }
    }

    return dp[0][n - 1];
}
```
First, initialize an `n` by `n` array (2D array) `dp` where `dp[i][j]` represents the minimum score/weight for the triangulation of the vertices from `i` to `j` (inclusive). The base case is when `dp[i][j]` is an edge in the polygon, in which case the weight is 0 since there is no triangle formed between those vertices.

Now, iterate through all possible lengths of the polygon from 3 to `n`. For each length, iterate through all possible vertex pairs (`i`, `j`) with the given length between them, and for each vertex `k` between `i` and `j`, consider the minimum possible weights with the current triangle formed by vertices (`i`, `j`, `k`). The weight of the considered triangles is calculated by taking the product of values at vertices `i`, `j`, and `k`, then add the weights for the other two triangles.

Finally, return the minimum score/weight `dp[0][n - 1]` which represents the triangulation of the whole polygon.


# Number of Days in a Month

- slug: number-of-days-in-a-month
- difficulty: Easy

Given a year `year` and a month `month`, return _the number of days of that month_.

**Example 1:**

**Input:** year = 1992, month = 7
**Output:** 31

**Example 2:**

**Input:** year = 2000, month = 2
**Output:** 29

**Example 3:**

**Input:** year = 1900, month = 2
**Output:** 28

**Constraints:**

*   `1583 <= year <= 2100`
*   `1 <= month <= 12`

## A solution in Java

```java
int numberOfDays(int year, int month) {
    if (month == 2) {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
            return 29;
        return 28;
    }
    if (month == 4 || month == 6 || month == 9 || month == 11)
        return 30;
    return 31;
}
```
The algorithm first checks if the given month is February. If it is, then it determines if the given year is a leap year. A leap year is a year that is divisible by 4 and not divisible by 100, or divisible by 400. If it is a leap year, it returns 29 as the number of days in February; otherwise, it returns 28.

If the given month is April, June, September, or November, the algorithm returns 30 as the number of days in that month. For all other months (January, March, May, July, August, October, and December), the algorithm returns 31 as the number of days in that month.

## A solution in C++

```cpp
int numberOfDays(int year, int month) {
    if(month == 2) {
        if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
            return 29;
        return 28;
    }
    if(month == 4 || month == 6 || month == 9 || month == 11)
        return 30;
    return 31;
}
```
The algorithm first checks if the given month is February. If it is, then it determines if the given year is a leap year. A leap year is a year that is divisible by 4 and not divisible by 100, or divisible by 400. If it is a leap year, it returns 29 as the number of days in February; otherwise, it returns 28.

If the given month is April, June, September, or November, the algorithm returns 30 as the number of days in that month. For all other months (January, March, May, July, August, October, and December), the algorithm returns 31 as the number of days in that month.

## A solution in Python

```python
def number_of_days(year, month):
    if month == 2:
        if (year % 4 == 0 and year % 100 != 0) or year % 400 == 0:
            return 29
        return 28
    if month in [4, 6, 9, 11]:
        return 30
    return 31
```
The algorithm first checks if the given month is February. If it is, then it determines if the given year is a leap year. A leap year is a year that is divisible by 4 and not divisible by 100, or divisible by 400. If it is a leap year, it returns 29 as the number of days in February; otherwise, it returns 28.

If the given month is April, June, September, or November, the algorithm returns 30 as the number of days in that month. For all other months (January, March, May, July, August, October, and December), the algorithm returns 31 as the number of days in that month.

## A solution in Javascript

```javascript
function numberOfDays(year, month) {
    if (month == 2) {
        if ((year % 4 == 0 && year % 100 != 0) || year % 400 == 0)
            return 29;
        return 28;
    }
    if (month == 4 || month == 6 || month == 9 || month == 11)
        return 30;
    return 31;
}
```
The algorithm first checks if the given month is February. If it is, then it determines if the given year is a leap year. A leap year is a year that is divisible by 4 and not divisible by 100, or divisible by 400. If it is a leap year, it returns 29 as the number of days in February; otherwise, it returns 28.

If the given month is April, June, September, or November, the algorithm returns 30 as the number of days in that month. For all other months (January, March, May, July, August, October, and December), the algorithm returns 31 as the number of days in that month.


# Remove Vowels from a String

- slug: remove-vowels-from-a-string
- difficulty: Easy

Given a string `s`, remove the vowels `'a'`, `'e'`, `'i'`, `'o'`, and `'u'` from it, and return the new string.

**Example 1:**

**Input:** s =  "leetcodeisacommunityforcoders "
**Output:**  "ltcdscmmntyfrcdrs "

**Example 2:**

**Input:** s =  "aeiou "
**Output:**  " "

**Constraints:**

*   `1 <= s.length <= 1000`
*   `s` consists of only lowercase English letters.

## A solution in Java

```java
public boolean isRobotBounded(String instructions) {
    int x = 0, y = 0, dir = 0;
    int[][] moves = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

    for (char c : instructions.toCharArray()) {
        if (c == 'G') {
            x += moves[dir][0];
            y += moves[dir][1];
        } else if (c == 'L') {
            dir = (dir + 3) % 4;
        } else {
            dir = (dir + 1) % 4;
        }
    }

    return (x == 0 && y == 0) || dir != 0;
}
```
1. Initialize (x, y) as the robot's initial position and direction as dir (0: north, 1: east, 2: south, 3: west).
2. Declare an array moves, which represents the movement in the x and y directions when going straight.
3. Iterate through instructions:
    - If the instruction is 'G', update x and y based on the current direction.
    - If the instruction is 'L', update dir as (dir + 3) % 4 to turn left (counter-clockwise).
    - If the instruction is 'R', update dir as (dir + 1) % 4 to turn right (clockwise).
4. If the robot reaches the starting position (0,0) or its direction is not north (dir != 0), then it stays in a circle. Otherwise, it doesn't.

## A solution in C++

```cpp
bool isRobotBounded(string instructions) {
    int x = 0, y = 0, dir = 0;
    vector<vector<int>> moves {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

    for (char c : instructions) {
        if (c == 'G') {
            x += moves[dir][0];
            y += moves[dir][1];
        } else if (c == 'L') {
            dir = (dir + 3) % 4;
        } else {
            dir = (dir + 1) % 4;
        }
    }

    return (x == 0 && y == 0) || dir != 0;
}
```
1. Initialize (x, y) as the robot's initial position and direction as dir (0: north, 1: east, 2: south, 3: west).
2. Declare an array moves, which represents the movement in the x and y directions when going straight.
3. Iterate through instructions:
    - If the instruction is 'G', update x and y based on the current direction.
    - If the instruction is 'L', update dir as (dir + 3) % 4 to turn left (counter-clockwise).
    - If the instruction is 'R', update dir as (dir + 1) % 4 to turn right (clockwise).
4. If the robot reaches the starting position (0,0) or its direction is not north (dir != 0), then it stays in a circle. Otherwise, it doesn't.

## A solution in Python

```python
def is_robot_bounded(instructions: str) -> bool:
    x, y, dir = 0, 0, 0
    moves = [(0, 1), (1, 0), (0, -1), (-1, 0)]

    for c in instructions:
        if c == 'G':
            x += moves[dir][0]
            y += moves[dir][1]
        elif c == 'L':
            dir = (dir + 3) % 4
        else:
            dir = (dir + 1) % 4

    return (x == 0 and y == 0) or dir != 0
```
1. Initialize (x, y) as the robot's initial position and direction as dir (0: north, 1: east, 2: south, 3: west).
2. Declare an array moves, which represents the movement in the x and y directions when going straight.
3. Iterate through instructions:
    - If the instruction is 'G', update x and y based on the current direction.
    - If the instruction is 'L', update dir as (dir + 3) % 4 to turn left (counter-clockwise).
    - If the instruction is 'R', update dir as (dir + 1) % 4 to turn right (clockwise).
4. If the robot reaches the starting position (0,0) or its direction is not north (dir != 0), then it stays in a circle. Otherwise, it doesn't.

## A solution in Javascript

```javascript
function isRobotBounded(instructions) {
    let x = 0, y = 0, dir = 0;
    const moves = [[0, 1], [1, 0], [0, -1], [-1, 0]];

    for (const c of instructions) {
        if (c === 'G') {
            x += moves[dir][0];
            y += moves[dir][1];
        } else if (c === 'L') {
            dir = (dir + 3) % 4;
        } else {
            dir = (dir + 1) % 4;
        }
    }

    return (x === 0 && y === 0) || dir !== 0;
}
```
1. Initialize (x, y) as the robot's initial position and direction as dir (0: north, 1: east, 2: south, 3: west).
2. Declare an array moves, which represents the movement in the x and y directions when going straight.
3. Iterate through instructions:
    - If the instruction is 'G', update x and y based on the current direction.
    - If the instruction is 'L', update dir as (dir + 3) % 4 to turn left (counter-clockwise).
    - If the instruction is 'R', update dir as (dir + 1) % 4 to turn right (clockwise).
4. If the robot reaches the starting position (0,0) or its direction is not north (dir != 0), then it stays in a circle. Otherwise, it doesn't.


# Maximum Average Subtree

- slug: maximum-average-subtree
- difficulty: Medium

Given the `root` of a binary tree, return _the maximum **average** value of a **subtree** of that tree_. Answers within `10-5` of the actual answer will be accepted.

A **subtree** of a tree is any node of that tree plus all its descendants.

The **average** value of a tree is the sum of its values, divided by the number of nodes.

**Example 1:**

**Input:** root = \[5,6,1\]
**Output:** 6.00000
**Explanation:**
For the node with value = 5 we have an average of (5 + 6 + 1) / 3 = 4.
For the node with value = 6 we have an average of 6 / 1 = 6.
For the node with value = 1 we have an average of 1 / 1 = 1.
So the answer is 6 which is the maximum.

**Example 2:**

**Input:** root = \[0,null,1\]
**Output:** 1.00000

**Constraints:**

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

## A solution in Java

```java
import java.util.*;

public int[] gardenNoAdj(int n, int[][] paths) {
    List<Set<Integer>> graph = new ArrayList<>();
    for (int i = 0; i < n; i++) {
        graph.add(new HashSet<>());
    }
    for (int[] path : paths) {
        graph.get(path[0] - 1).add(path[1] - 1);
        graph.get(path[1] - 1).add(path[0] - 1);
    }
    int[] result = new int[n];
    for (int i = 0; i < n; i++) {
        Set<Integer> usedFlowers = new HashSet<>();
        for (int neighbor : graph.get(i)) {
            usedFlowers.add(result[neighbor]);
        }
        for (int flower = 1; flower <= 4; flower++) {
            if (!usedFlowers.contains(flower)) {
                result[i] = flower;
                break;
            }
        }
    }
    return result;
}
```
The algorithm first represents the bidirectional paths with an adjacent graph structure. Then, for each garden (node), it iterates through its neighbors to keep track of the flowers already represented at adjacent gardens. Finally, it checks the remaining possible flowers (from the 4 types) which haven't been used in neighboring gardens, and assigns that flower type to the current garden. This process is repeated until a flower type is assigned to all gardens, ensuring that no two connected gardens have the same type of flower.

## A solution in C++

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

std::vector<int> gardenNoAdj(int n, std::vector<std::vector<int>>& paths) {
    std::vector<std::unordered_set<int>> graph(n);
    for (const auto& path : paths) {
        graph[path[0] - 1].insert(path[1] - 1);
        graph[path[1] - 1].insert(path[0] - 1);
    }

    std::vector<int> result(n);
    for (int i = 0; i < n; ++i) {
        std::unordered_set<int> used_flowers;
        for (int neighbor : graph[i]) {
            used_flowers.insert(result[neighbor]);
        }
        for (int flower = 1; flower <= 4; ++flower) {
            if (used_flowers.count(flower) == 0) {
                result[i] = flower;
                break;
            }
        }
    }
    return result;
}
```
The algorithm first represents the bidirectional paths with an adjacent graph structure. Then, for each garden (node), it iterates through its neighbors to keep track of the flowers already represented at adjacent gardens. Finally, it checks the remaining possible flowers (from the 4 types) which haven't been used in neighboring gardens, and assigns that flower type to the current garden. This process is repeated until a flower type is assigned to all gardens, ensuring that no two connected gardens have the same type of flower.

## A solution in Python

```python
from collections import defaultdict

def gardenNoAdj(n, paths):
    graph = defaultdict(set)
    for x, y in paths:
        graph[x - 1].add(y - 1)
        graph[y - 1].add(x - 1)

    result = [0] * n
    for i in range(n):
        used_flowers = {result[neighbor] for neighbor in graph[i]}
        for flower in range(1, 5):
            if flower not in used_flowers:
                result[i] = flower
                break
    return result
```
The algorithm first represents the bidirectional paths with an adjacent graph structure. Then, for each garden (node), it iterates through its neighbors to keep track of the flowers already represented at adjacent gardens. Finally, it checks the remaining possible flowers (from the 4 types) which haven't been used in neighboring gardens, and assigns that flower type to the current garden. This process is repeated until a flower type is assigned to all gardens, ensuring that no two connected gardens have the same type of flower.

## A solution in Javascript

```javascript
function gardenNoAdj(n, paths) {
    const graph = Array.from({ length: n }, () => new Set());

    for (const [x, y] of paths) {
        graph[x - 1].add(y - 1);
        graph[y - 1].add(x - 1);
    }

    const result = Array(n).fill(0);
    for (let i = 0; i < n; i++) {
        const usedFlowers = new Set(graph[i].map(neighbor => result[neighbor]));

        for (let flower = 1; flower <= 4; flower++) {
            if (!usedFlowers.has(flower)) {
                result[i] = flower;
                break;
            }
        }
    }
    return result;
}
```
The algorithm first represents the bidirectional paths with an adjacent graph structure. Then, for each garden (node), it iterates through its neighbors to keep track of the flowers already represented at adjacent gardens. Finally, it checks the remaining possible flowers (from the 4 types) which haven't been used in neighboring gardens, and assigns that flower type to the current garden. This process is repeated until a flower type is assigned to all gardens, ensuring that no two connected gardens have the same type of flower.


# Divide Array Into Increasing Sequences

- slug: divide-array-into-increasing-sequences
- difficulty: Hard

Given an integer array `nums` sorted in non-decreasing order and an integer `k`, return `true` _if this array can be divided into one or more disjoint increasing subsequences of length at least_ `k`_, or_ `false` _otherwise_.

**Example 1:**

**Input:** nums = \[1,2,2,3,3,4,4\], k = 3
**Output:** true
**Explanation:** The array can be divided into two subsequences \[1,2,3,4\] and \[2,3,4\] with lengths at least 3 each.

**Example 2:**

**Input:** nums = \[5,6,6,7,8\], k = 3
**Output:** false
**Explanation:** There is no way to divide the array using the conditions required.

**Constraints:**

*   `1 <= k <= nums.length <= 105`
*   `1 <= nums[i] <= 105`
*   `nums` is sorted in non-decreasing order.

## A solution in Java

```java
public int maxSumAfterPartitioning(int[] arr, int k) {
    int n = arr.length;
    int[] dp = new int[n + 1];
    for (int i = 1; i <= n; ++i) {
        int current_max = 0;
        for (int j = 1; j <= k && i - j >= 0; ++j) {
            current_max = Math.max(current_max, arr[i - j]);
            dp[i] = Math.max(dp[i], dp[i - j] + current_max * j);
        }
    }
    return dp[n];
}
```
1. Initialize a dp array of size n+1, where n is the length of arr, with every element set to 0. dp[i] represents the maximum sum up to the index i.
2. Iterate over array indices from 1 to n.
   a. For each index i, initialize a variable `current_max` to store the maximum element found in the subarray.
   b. Iterate over subarray lengths from 1 to k:
      i. If the index i minus the subarray length is not negative, then find the maximum of `current_max` and the value located at arr[i - subarray length].
      ii. Update the value of dp[i] with the maximum between the current value at dp[i] and the value found in dp[i - subarray length] + the product of current_max * subarray length.
3. At the end, return the value stored in the last index of dp, which represents the maximum partitioned sum of the entire array.

## A solution in C++

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

int maxSumAfterPartitioning(vector<int>& arr, int k) {
    int n = arr.size();
    vector<int> dp(n + 1, 0);
    for (int i = 1; i <= n; ++i) {
        int current_max = 0;
        for (int j = 1; j <= k && i - j >= 0; ++j) {
            current_max = max(current_max, arr[i - j]);
            dp[i] = max(dp[i], dp[i - j] + current_max * j);
        }
    }
    return dp[n];
}
```
1. Initialize a dp array of size n+1, where n is the length of arr, with every element set to 0. dp[i] represents the maximum sum up to the index i.
2. Iterate over array indices from 1 to n.
   a. For each index i, initialize a variable `current_max` to store the maximum element found in the subarray.
   b. Iterate over subarray lengths from 1 to k:
      i. If the index i minus the subarray length is not negative, then find the maximum of `current_max` and the value located at arr[i - subarray length].
      ii. Update the value of dp[i] with the maximum between the current value at dp[i] and the value found in dp[i - subarray length] + the product of current_max * subarray length.
3. At the end, return the value stored in the last index of dp, which represents the maximum partitioned sum of the entire array.

## A solution in Python

```python
def maxSumAfterPartitioning(arr: list, k: int) -> int:
    n = len(arr)
    dp = [0] * (n + 1)
    for i in range(1, n + 1):
        current_max = 0
        for j in range(1, k + 1):
            if i - j < 0:
                break
            current_max = max(current_max, arr[i - j])
            dp[i] = max(dp[i], dp[i - j] + current_max * j)
    return dp[n]
```
1. Initialize a dp array of size n+1, where n is the length of arr, with every element set to 0. dp[i] represents the maximum sum up to the index i.
2. Iterate over array indices from 1 to n.
   a. For each index i, initialize a variable `current_max` to store the maximum element found in the subarray.
   b. Iterate over subarray lengths from 1 to k:
      i. If the index i minus the subarray length is not negative, then find the maximum of `current_max` and the value located at arr[i - subarray length].
      ii. Update the value of dp[i] with the maximum between the current value at dp[i] and the value found in dp[i - subarray length] + the product of current_max * subarray length.
3. At the end, return the value stored in the last index of dp, which represents the maximum partitioned sum of the entire array.

## A solution in Javascript

```javascript
function maxSumAfterPartitioning(arr, k) {
    const n = arr.length;
    const dp = new Array(n + 1).fill(0);
    for (let i = 1; i <= n; ++i) {
        let current_max = 0;
        for (let j = 1; j <= k && i - j >= 0; ++j) {
            current_max = Math.max(current_max, arr[i - j]);
            dp[i] = Math.max(dp[i], dp[i - j] + current_max * j);
        }
    }
    return dp[n];
}
```
1. Initialize a dp array of size n+1, where n is the length of arr, with every element set to 0. dp[i] represents the maximum sum up to the index i.
2. Iterate over array indices from 1 to n.
   a. For each index i, initialize a variable `current_max` to store the maximum element found in the subarray.
   b. Iterate over subarray lengths from 1 to k:
      i. If the index i minus the subarray length is not negative, then find the maximum of `current_max` and the value located at arr[i - subarray length].
      ii. Update the value of dp[i] with the maximum between the current value at dp[i] and the value found in dp[i - subarray length] + the product of current_max * subarray length.
3. At the end, return the value stored in the last index of dp, which represents the maximum partitioned sum of the entire array.


# Relative Sort Array

- slug: relative-sort-array
- difficulty: Easy

Given two arrays `arr1` and `arr2`, the elements of `arr2` are distinct, and all elements in `arr2` are also in `arr1`.

Sort the elements of `arr1` such that the relative ordering of items in `arr1` are the same as in `arr2`. Elements that do not appear in `arr2` should be placed at the end of `arr1` in **ascending** order.

**Example 1:**

**Input:** arr1 = \[2,3,1,3,2,4,6,7,9,2,19\], arr2 = \[2,1,4,3,9,6\]
**Output:** \[2,2,2,1,4,3,3,9,6,7,19\]

**Example 2:**

**Input:** arr1 = \[28,6,22,8,44,17\], arr2 = \[22,28,8,6\]
**Output:** \[22,28,8,6,17,44\]

**Constraints:**

*   `1 <= arr1.length, arr2.length <= 1000`
*   `0 <= arr1[i], arr2[i] <= 1000`
*   All the elements of `arr2` are **distinct**.
*   Each `arr2[i]` is in `arr1`.

## A solution in Java

```java
public String longestDupSubstring(String s) {
    int n = s.length();
    String longest_duplicate = "";
    for (int length = n - 1; length > 0; --length) {
        for (int i = 0; i <= n - length; ++i) {
            String substring = s.substring(i, i + length);
            if (s.indexOf(substring, i + 1) != -1) {
                longest_duplicate = substring;
                return longest_duplicate;
            }
        }
    }
    return longest_duplicate;
}
```
The algorithm starts with defining the longest possible duplicate string length which is the length of the input string minus one. Then, we iterate through all possible substring lengths from the longest to the shortest.

For each substring length, we iterate through the input string to check if there's a duplicate substring. We obtain a substring with the starting position `i` and the current length, then find if there's another occurrence of this substring in the input string. If there's one, we return the current substring as the longest duplicate substring.

If we finish iterating through all possible substring lengths without finding any duplicate substrings, we return an empty string.

## A solution in C++

```cpp
#include <string>

std::string longestDupSubstring(std::string s) {
    int n = s.length();
    std::string longest_duplicate;
    for (int length = n - 1; length > 0; --length) {
        for (int i = 0; i <= n - length; ++i) {
            std::string substring = s.substr(i, length);
            if (s.find(substring, i + 1) != std::string::npos) {
                longest_duplicate = substring;
                return longest_duplicate;
            }
        }
    }
    return longest_duplicate;
}
```
The algorithm starts with defining the longest possible duplicate string length which is the length of the input string minus one. Then, we iterate through all possible substring lengths from the longest to the shortest.

For each substring length, we iterate through the input string to check if there's a duplicate substring. We obtain a substring with the starting position `i` and the current length, then find if there's another occurrence of this substring in the input string. If there's one, we return the current substring as the longest duplicate substring.

If we finish iterating through all possible substring lengths without finding any duplicate substrings, we return an empty string.

## A solution in Python

```python
def longest_dup_substring(s):
    n = len(s)
    longest_duplicate = ""
    for length in range(n - 1, 0, -1):
        for i in range(n - length + 1):
            substring = s[i:i + length]
            if s.find(substring, i + 1) != -1:
                longest_duplicate = substring
                return longest_duplicate
    return longest_duplicate
```
The algorithm starts with defining the longest possible duplicate string length which is the length of the input string minus one. Then, we iterate through all possible substring lengths from the longest to the shortest.

For each substring length, we iterate through the input string to check if there's a duplicate substring. We obtain a substring with the starting position `i` and the current length, then find if there's another occurrence of this substring in the input string. If there's one, we return the current substring as the longest duplicate substring.

If we finish iterating through all possible substring lengths without finding any duplicate substrings, we return an empty string.

## A solution in Javascript

```javascript
function longestDupSubstring(s) {
    const n = s.length;
    let longest_duplicate = "";
    for (let length = n - 1; length > 0; --length) {
        for (let i = 0; i <= n - length; ++i) {
            const substring = s.substring(i, i + length);
            if (s.indexOf(substring, i + 1) !== -1) {
                longest_duplicate = substring;
                return longest_duplicate;
            }
        }
    }
    return longest_duplicate;
}
```
The algorithm starts with defining the longest possible duplicate string length which is the length of the input string minus one. Then, we iterate through all possible substring lengths from the longest to the shortest.

For each substring length, we iterate through the input string to check if there's a duplicate substring. We obtain a substring with the starting position `i` and the current length, then find if there's another occurrence of this substring in the input string. If there's one, we return the current substring as the longest duplicate substring.

If we finish iterating through all possible substring lengths without finding any duplicate substrings, we return an empty string.


# Lowest Common Ancestor of Deepest Leaves

- slug: lowest-common-ancestor-of-deepest-leaves
- difficulty: Medium

Given the `root` of a binary tree, return _the lowest common ancestor of its deepest leaves_.

Recall that:

*   The node of a binary tree is a leaf if and only if it has no children
*   The depth of the root of the tree is `0`. if the depth of a node is `d`, the depth of each of its children is `d + 1`.
*   The lowest common ancestor of a set `S` of nodes, is the node `A` with the largest depth such that every node in `S` is in the subtree with root `A`.

**Example 1:**

**Input:** root = \[3,5,1,6,2,0,8,null,null,7,4\]
**Output:** \[2,7,4\]
**Explanation:** We return the node with value 2, colored in yellow in the diagram.
The nodes coloured in blue are the deepest leaf-nodes of the tree.
Note that nodes 6, 0, and 8 are also leaf nodes, but the depth of them is 2, but the depth of nodes 7 and 4 is 3.

**Example 2:**

**Input:** root = \[1\]
**Output:** \[1\]
**Explanation:** The root is the deepest node in the tree, and it's the lca of itself.

**Example 3:**

**Input:** root = \[0,1,3,null,2\]
**Output:** \[2\]
**Explanation:** The deepest leaf node in the tree is 2, the lca of one node is itself.

**Constraints:**

*   The number of nodes in the tree will be in the range `[1, 1000]`.
*   `0 <= Node.val <= 1000`
*   The values of the nodes in the tree are **unique**.

**Note:** This question is the same as 865: [https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/](https://leetcode.com/problems/smallest-subtree-with-all-the-deepest-nodes/)

## A solution in Java

```java
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
}

class Pair {
    TreeNode node;
    int depth;
}

public Pair findLCAUtil(TreeNode root) {
    if (root == null) {
        return new Pair(null, 0);
    }

    Pair leftLCA = findLCAUtil(root.left);
    Pair rightLCA = findLCAUtil(root.right);

    if (leftLCA.depth > rightLCA.depth) {
        leftLCA.depth++;
        return leftLCA;
    } else if (leftLCA.depth < rightLCA.depth) {
        rightLCA.depth++;
        return rightLCA;
    } else {
        return new Pair(root, leftLCA.depth + 1);
    }
}

public TreeNode lcaDeepestLeaves(TreeNode root) {
    return findLCAUtil(root).node;
}
```
1. Traverse the binary tree in a depth-first manner.
2. For each node, find the lowest common ancestor (LCA) of its left and right children.
3. Update the depth of the current LCA accordingly.
4. When the children nodes don't exist or have the same depth, return the current node as the LCA.
5. The function returns a pair/tree tuple (node, depth) representing the LCA of the deepest leaves.

We recursively find the LCA of the left and right subtrees and the depth of the deepest leaves in those subtrees. We compare the depth of left and right subtrees, and the tree node with the highest depth will be returned. If the depth of the subtrees is the same, return the current node as it is the lowest common ancestor of its deepest leaves.

## A solution in C++

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

pair<TreeNode*, int> findLCAUtil(TreeNode* root) {
    if (root == nullptr) {
        return {nullptr, 0};
    }

    pair<TreeNode*, int> leftLCA = findLCAUtil(root->left);
    pair<TreeNode*, int> rightLCA = findLCAUtil(root->right);

    if (leftLCA.second > rightLCA.second) {
        return {leftLCA.first, leftLCA.second + 1};
    } else if (leftLCA.second < rightLCA.second) {
        return {rightLCA.first, rightLCA.second + 1};
    } else {
        return {root, leftLCA.second + 1};
    }
}

TreeNode* lcaDeepestLeaves(TreeNode* root) {
    return findLCAUtil(root).first;
}
```
1. Traverse the binary tree in a depth-first manner.
2. For each node, find the lowest common ancestor (LCA) of its left and right children.
3. Update the depth of the current LCA accordingly.
4. When the children nodes don't exist or have the same depth, return the current node as the LCA.
5. The function returns a pair/tree tuple (node, depth) representing the LCA of the deepest leaves.

We recursively find the LCA of the left and right subtrees and the depth of the deepest leaves in those subtrees. We compare the depth of left and right subtrees, and the tree node with the highest depth will be returned. If the depth of the subtrees is the same, return the current node as it is the lowest common ancestor of its deepest leaves.

## A solution in Python

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

def find_lca_util(root):
    if root is None:
        return None, 0

    left_lca, left_depth = find_lca_util(root.left)
    right_lca, right_depth = find_lca_util(root.right)

    if left_depth > right_depth:
        return left_lca, left_depth + 1
    elif left_depth < right_depth:
        return right_lca, right_depth + 1
    else:
        return root, left_depth + 1

def lca_deepest_leaves(root):
    return find_lca_util(root)[0]
```
1. Traverse the binary tree in a depth-first manner.
2. For each node, find the lowest common ancestor (LCA) of its left and right children.
3. Update the depth of the current LCA accordingly.
4. When the children nodes don't exist or have the same depth, return the current node as the LCA.
5. The function returns a pair/tree tuple (node, depth) representing the LCA of the deepest leaves.

We recursively find the LCA of the left and right subtrees and the depth of the deepest leaves in those subtrees. We compare the depth of left and right subtrees, and the tree node with the highest depth will be returned. If the depth of the subtrees is the same, return the current node as it is the lowest common ancestor of its deepest leaves.

## A solution in Javascript

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

function findLCAUtil(root) {
    if (root === null) {
        return { node: null, depth: 0 };
    }

    let leftLCA = findLCAUtil(root.left);
    let rightLCA = findLCAUtil(root.right);

    if (leftLCA.depth > rightLCA.depth) {
        leftLCA.depth++;
        return leftLCA;
    } else if (leftLCA.depth < rightLCA.depth) {
        rightLCA.depth++;
        return rightLCA;
    } else {
        return { node: root, depth: leftLCA.depth + 1 };
    }
}

function lcaDeepestLeaves(root) {
    return findLCAUtil(root).node;
}
```
1. Traverse the binary tree in a depth-first manner.
2. For each node, find the lowest common ancestor (LCA) of its left and right children.
3. Update the depth of the current LCA accordingly.
4. When the children nodes don't exist or have the same depth, return the current node as the LCA.
5. The function returns a pair/tree tuple (node, depth) representing the LCA of the deepest leaves.

We recursively find the LCA of the left and right subtrees and the depth of the deepest leaves in those subtrees. We compare the depth of left and right subtrees, and the tree node with the highest depth will be returned. If the depth of the subtrees is the same, return the current node as it is the lowest common ancestor of its deepest leaves.


# Longest Well-Performing Interval

- slug: longest-well-performing-interval
- difficulty: Medium

We are given `hours`, a list of the number of hours worked per day for a given employee.

A day is considered to be a _tiring day_ if and only if the number of hours worked is (strictly) greater than `8`.

A _well-performing interval_ is an interval of days for which the number of tiring days is strictly larger than the number of non-tiring days.

Return the length of the longest well-performing interval.

**Example 1:**

**Input:** hours = \[9,9,6,0,6,6,9\]
**Output:** 3
**Explanation:** The longest well-performing interval is \[9,9,6\].

**Example 2:**

**Input:** hours = \[6,6,6\]
**Output:** 0

**Constraints:**

*   `1 <= hours.length <= 104`
*   `0 <= hours[i] <= 16`

## A solution in Java

```java
import java.util.HashMap;

public int longestWellPerformingInterval(int[] hours) {
    int sum = 0;
    int longest = 0;
    HashMap<Integer, Integer> firstSumIndex = new HashMap<>();

    for (int i = 0; i < hours.length; i++) {
        sum += (hours[i] > 8) ? 1 : -1;
        if (sum > 0) {
            longest = i + 1;
        } else {
            if (firstSumIndex.containsKey(sum - 1)) {
                longest = Math.max(longest, i - firstSumIndex.get(sum - 1));
            }
            if (!firstSumIndex.containsKey(sum)) {
                firstSumIndex.put(sum, i);
            }
        }
    }
    return longest;
}
```
The algorithm iterates through the input list, representing the hours worked. It keeps track of the cumulative sum of tiring and non-tiring days, incrementing the sum by 1 for a tiring day, and decrementing by 1 for a non-tiring day.

During the iteration, it checks if the sum is greater than 0, meaning there are more tiring days than non-tiring days up to the current index. If that's the case, the length of the well-performing interval is updated as the current index plus 1. If the sum is less than or equal to 0, the algorithm checks if the sum minus 1 exists in the dictionary of first sum occurrence indices; if it does, it updates the length of the well-performing interval according to this first occurrence index.

Finally, if the current sum hasn't been encountered before, the algorithm adds the current index as the first occurrence of the sum in the `first_sum_index` dictionary.

By the end of the iteration, the maximum length of a well-performing interval is found.

## A solution in C++

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

int longestWellPerformingInterval(std::vector<int> &hours) {
    int sum = 0;
    int longest = 0;
    std::unordered_map<int, int> first_sum_index;

    for (int i = 0; i < hours.size(); ++i) {
        sum += (hours[i] > 8) ? 1 : -1;
        if (sum > 0) {
            longest = i + 1;
        } else {
            if (first_sum_index.find(sum - 1) != first_sum_index.end()) {
                longest = std::max(longest, i - first_sum_index[sum - 1]);
            }
            if (first_sum_index.find(sum) == first_sum_index.end()) {
                first_sum_index[sum] = i;
            }
        }
    }
    return longest;
}
```
The algorithm iterates through the input list, representing the hours worked. It keeps track of the cumulative sum of tiring and non-tiring days, incrementing the sum by 1 for a tiring day, and decrementing by 1 for a non-tiring day.

During the iteration, it checks if the sum is greater than 0, meaning there are more tiring days than non-tiring days up to the current index. If that's the case, the length of the well-performing interval is updated as the current index plus 1. If the sum is less than or equal to 0, the algorithm checks if the sum minus 1 exists in the dictionary of first sum occurrence indices; if it does, it updates the length of the well-performing interval according to this first occurrence index.

Finally, if the current sum hasn't been encountered before, the algorithm adds the current index as the first occurrence of the sum in the `first_sum_index` dictionary.

By the end of the iteration, the maximum length of a well-performing interval is found.

## A solution in Python

```python
def longestWellPerformingInterval(hours):
    sum = 0
    longest = 0
    first_sum_index = {}

    for i, hour in enumerate(hours):
        sum += 1 if hour > 8 else -1
        if sum > 0:
            longest = i + 1
        else:
            if sum - 1 in first_sum_index:
                longest = max(longest, i - first_sum_index[sum - 1])
            if sum not in first_sum_index:
                first_sum_index[sum] = i

    return longest
```
The algorithm iterates through the input list, representing the hours worked. It keeps track of the cumulative sum of tiring and non-tiring days, incrementing the sum by 1 for a tiring day, and decrementing by 1 for a non-tiring day.

During the iteration, it checks if the sum is greater than 0, meaning there are more tiring days than non-tiring days up to the current index. If that's the case, the length of the well-performing interval is updated as the current index plus 1. If the sum is less than or equal to 0, the algorithm checks if the sum minus 1 exists in the dictionary of first sum occurrence indices; if it does, it updates the length of the well-performing interval according to this first occurrence index.

Finally, if the current sum hasn't been encountered before, the algorithm adds the current index as the first occurrence of the sum in the `first_sum_index` dictionary.

By the end of the iteration, the maximum length of a well-performing interval is found.

## A solution in Javascript

```javascript
function longestWellPerformingInterval(hours) {
    let sum = 0;
    let longest = 0;
    let firstSumIndex = {};

    for (let i = 0; i < hours.length; i++) {
        sum += (hours[i] > 8) ? 1 : -1;
        if (sum > 0) {
            longest = i + 1;
        } else {
            if (sum - 1 in firstSumIndex) {
                longest = Math.max(longest, i - firstSumIndex[sum - 1]);
            }
            if (!(sum in firstSumIndex)) {
                firstSumIndex[sum] = i;
            }
        }
    }
    return longest;
}
```
The algorithm iterates through the input list, representing the hours worked. It keeps track of the cumulative sum of tiring and non-tiring days, incrementing the sum by 1 for a tiring day, and decrementing by 1 for a non-tiring day.

During the iteration, it checks if the sum is greater than 0, meaning there are more tiring days than non-tiring days up to the current index. If that's the case, the length of the well-performing interval is updated as the current index plus 1. If the sum is less than or equal to 0, the algorithm checks if the sum minus 1 exists in the dictionary of first sum occurrence indices; if it does, it updates the length of the well-performing interval according to this first occurrence index.

Finally, if the current sum hasn't been encountered before, the algorithm adds the current index as the first occurrence of the sum in the `first_sum_index` dictionary.

By the end of the iteration, the maximum length of a well-performing interval is found.