# Longest Increasing Subsequence

- slug: longest-increasing-subsequence
- difficulty: Medium

Given an integer array `nums`, return _the length of the longest **strictly increasing**_ _**subsequence**_.

**Example 1:**

**Input:** nums = \[10,9,2,5,3,7,101,18\]
**Output:** 4
**Explanation:** The longest increasing subsequence is \[2,3,7,101\], therefore the length is 4.

**Example 2:**

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

**Example 3:**

**Input:** nums = \[7,7,7,7,7,7,7\]
**Output:** 1

**Constraints:**

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

**Follow up:** Can you come up with an algorithm that runs in `O(n log(n))` time complexity?

## A solution in Java

```java
public int lengthOfLIS(int[] nums) {
    int[] dp = new int[nums.length];
    int max_length = 1;
    Arrays.fill(dp, 1);
    for (int i = 1; i < nums.length; i++) {
        for (int j = 0; j < i; j++) {
            if (nums[i] > nums[j]) {
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
        max_length = Math.max(max_length, dp[i]);
    }
    return max_length;
}
```
The algorithm employs dynamic programming to solve the problem. The algorithm initializes an array `dp` of the same length as the input array `nums`, and initializes all its elements with the value 1, indicating that at least a single element can be part of the longest increasing subsequence.

Then, it employs a nested loop to iterate over the input array from the second element onwards. In the inner loop, we compare each element from the 0th index to `i-1` with the current element at `i`. If the current element is greater than the previous element, we update the `dp[i]` value by taking the maximum of the current `dp[i]` value and the `dp[j]` value of the previous element + 1, which indicates the length of the increasing subsequence.

Finally, we update the max_length variable after each outer loop by taking its maximum from the array `dp`. After completing the iterations, we return the length of the longest increasing subsequence.

## A solution in C++

```cpp
int lengthOfLIS(vector<int>& nums) {
    vector<int> dp(nums.size(), 1);
    int max_length = 1;
    for (int i = 1; i < nums.size(); i++) {
        for (int j = 0; j < i; j++) {
            if (nums[i] > nums[j]) {
                dp[i] = max(dp[i], dp[j] + 1);
            }
        }
        max_length = max(max_length, dp[i]);
    }
    return max_length;
}
```
The algorithm employs dynamic programming to solve the problem. The algorithm initializes an array `dp` of the same length as the input array `nums`, and initializes all its elements with the value 1, indicating that at least a single element can be part of the longest increasing subsequence.

Then, it employs a nested loop to iterate over the input array from the second element onwards. In the inner loop, we compare each element from the 0th index to `i-1` with the current element at `i`. If the current element is greater than the previous element, we update the `dp[i]` value by taking the maximum of the current `dp[i]` value and the `dp[j]` value of the previous element + 1, which indicates the length of the increasing subsequence.

Finally, we update the max_length variable after each outer loop by taking its maximum from the array `dp`. After completing the iterations, we return the length of the longest increasing subsequence.

## A solution in Python

```python
def lengthOfLIS(nums):
    dp = [1] * len(nums)
    max_length = 1
    for i in range(1, len(nums)):
        for j in range(i):
            if nums[i] > nums[j]:
                dp[i] = max(dp[i], dp[j] + 1)
        max_length = max(max_length, dp[i])
    return max_length
```
The algorithm employs dynamic programming to solve the problem. The algorithm initializes an array `dp` of the same length as the input array `nums`, and initializes all its elements with the value 1, indicating that at least a single element can be part of the longest increasing subsequence.

Then, it employs a nested loop to iterate over the input array from the second element onwards. In the inner loop, we compare each element from the 0th index to `i-1` with the current element at `i`. If the current element is greater than the previous element, we update the `dp[i]` value by taking the maximum of the current `dp[i]` value and the `dp[j]` value of the previous element + 1, which indicates the length of the increasing subsequence.

Finally, we update the max_length variable after each outer loop by taking its maximum from the array `dp`. After completing the iterations, we return the length of the longest increasing subsequence.

## A solution in Javascript

```javascript
function lengthOfLIS(nums) {
    const dp = new Array(nums.length).fill(1);
    let max_length = 1;
    for (let i = 1; i < nums.length; i++) {
        for (let j = 0; j < i; j++) {
            if (nums[i] > nums[j]) {
                dp[i] = Math.max(dp[i], dp[j] + 1);
            }
        }
        max_length = Math.max(max_length, dp[i]);
    }
    return max_length;
}
```
The algorithm employs dynamic programming to solve the problem. The algorithm initializes an array `dp` of the same length as the input array `nums`, and initializes all its elements with the value 1, indicating that at least a single element can be part of the longest increasing subsequence.

Then, it employs a nested loop to iterate over the input array from the second element onwards. In the inner loop, we compare each element from the 0th index to `i-1` with the current element at `i`. If the current element is greater than the previous element, we update the `dp[i]` value by taking the maximum of the current `dp[i]` value and the `dp[j]` value of the previous element + 1, which indicates the length of the increasing subsequence.

Finally, we update the max_length variable after each outer loop by taking its maximum from the array `dp`. After completing the iterations, we return the length of the longest increasing subsequence.


# Remove Invalid Parentheses

- slug: remove-invalid-parentheses
- difficulty: Hard

Given a string `s` that contains parentheses and letters, remove the minimum number of invalid parentheses to make the input string valid.

Return _a list of **unique strings** that are valid with the minimum number of removals_. You may return the answer in **any order**.

**Example 1:**

**Input:** s =  "()())() "
**Output:** \[ "(())() ", "()()() "\]

**Example 2:**

**Input:** s =  "(a)())() "
**Output:** \[ "(a())() ", "(a)()() "\]

**Example 3:**

**Input:** s =  ")( "
**Output:** \[ " "\]

**Constraints:**

*   `1 <= s.length <= 25`
*   `s` consists of lowercase English letters and parentheses `'('` and `')'`.
*   There will be at most `20` parentheses in `s`.

## A solution in Java

```java
import java.util.*;

class Solution {
    public List<String> removeInvalidParentheses(String s) {
        Set<String> visited = new HashSet<>();
        Queue<String> queue = new LinkedList<>();
        List<String> result = new ArrayList<>();
        boolean found = false;

        visited.add(s);
        queue.offer(s);

        while (!queue.isEmpty()) {
            String current = queue.poll();

            if (isValid(current)) {
                found = true;
                result.add(current);
            }

            if (found) continue;

            for (int i = 0; i < current.length(); i++) {
                if (current.charAt(i) == '(' || current.charAt(i) == ')') {
                    String next = current.substring(0, i) + current.substring(i + 1);
                    if (!visited.contains(next)) {
                        visited.add(next);
                        queue.offer(next);
                    }
                }
            }
        }
        return result;
    }

    private boolean isValid(String s) {
        int count = 0;
        for (char c : s.toCharArray()) {
            if (c == '(') count++;
            if (c == ')') count--;
            if (count < 0) return false;
        }
        return count == 0;
    }
}
```
The algorithm uses a Breadth-First Search to find potential valid substrings. It first checks whether the current string is valid. If it finds a valid string, it continues to process any remaining strings in the queue, but it does not generate any more subsequences. If it has not found a valid string, it creates new substrings by removing one parentheses from the current string, adds them to the queue, and marks them as visited to avoid duplicity. This process repeats until the queue is empty or a valid string has been found. A count of open parentheses is maintained to check for string validity. The answer is returned as a list of valid strings.

## A solution in C++

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

using namespace std;

class Solution {
public:
    vector<string> removeInvalidParentheses(string s) {
        set<string> visited;
        queue<string> q;
        vector<string> result;
        bool found = false;

        visited.insert(s);
        q.push(s);

        while (!q.empty()) {
            string cur = q.front();
            q.pop();

            if (isValid(cur)) {
                found = true;
                result.push_back(cur);
            }

            if (found) continue;

            for (int i = 0; i < cur.length(); ++i) {
                if (cur[i] == '(' || cur[i] == ')') {
                    string next = cur.substr(0, i) + cur.substr(i+1);
                    if (visited.find(next) == visited.end()) {
                        visited.insert(next);
                        q.push(next);
                    }
                }
            }
        }
        return result;
    }

    bool isValid(const string &s) {
        int count = 0;
        for (char c : s) {
            if (c == '(') count++;
            if (c == ')') count--;
            if (count < 0) return false;
        }
        return count == 0;
    }
};
```
The algorithm uses a Breadth-First Search to find potential valid substrings. It first checks whether the current string is valid. If it finds a valid string, it continues to process any remaining strings in the queue, but it does not generate any more subsequences. If it has not found a valid string, it creates new substrings by removing one parentheses from the current string, adds them to the queue, and marks them as visited to avoid duplicity. This process repeats until the queue is empty or a valid string has been found. A count of open parentheses is maintained to check for string validity. The answer is returned as a list of valid strings.

## A solution in Python

```python
from collections import deque

class Solution:
    def removeInvalidParentheses(self, s: str):
        visited = set()
        queue = deque([s])
        result = []
        found = False

        while queue:
            cur = queue.popleft()

            if self.is_valid(cur):
                found = True
                result.append(cur)

            if found: continue

            for i in range(len(cur)):
                if cur[i] == '(' or cur[i] == ')':
                    next_str = cur[:i] + cur[i+1:]
                    if next_str not in visited:
                        visited.add(next_str)
                        queue.append(next_str)

        return result

    def is_valid(self, s: str) -> bool:
        count = 0
        for c in s:
            if c == '(': count += 1
            if c == ')':
                count -= 1
                if count < 0: return False
        return count == 0
```
The algorithm uses a Breadth-First Search to find potential valid substrings. It first checks whether the current string is valid. If it finds a valid string, it continues to process any remaining strings in the queue, but it does not generate any more subsequences. If it has not found a valid string, it creates new substrings by removing one parentheses from the current string, adds them to the queue, and marks them as visited to avoid duplicity. This process repeats until the queue is empty or a valid string has been found. A count of open parentheses is maintained to check for string validity. The answer is returned as a list of valid strings.

## A solution in Javascript

```javascript
class Solution {
    removeInvalidParentheses(s) {
        let visited = new Set();
        let queue = [s];
        let result = [];
        let found = false;

        while (queue.length > 0) {
            let cur = queue.shift();

            if (this.isValid(cur)) {
                found = true;
                result.push(cur);
            }

            if (found) continue;

            for (let i = 0; i < cur.length; i++) {
                if (cur[i] === '(' || cur[i] === ')') {
                    let next = cur.slice(0, i) + cur.slice(i + 1);
                    if (!visited.has(next)) {
                        visited.add(next);
                        queue.push(next);
                    }
                }
            }
        }
        return result;
    }

    isValid(s) {
        let count = 0;
        for (let c of s) {
            if (c === '(') count++;
            if (c === ')') count--;
            if (count < 0) return false;
        }
        return count === 0;
    }
}
```
The algorithm uses a Breadth-First Search to find potential valid substrings. It first checks whether the current string is valid. If it finds a valid string, it continues to process any remaining strings in the queue, but it does not generate any more subsequences. If it has not found a valid string, it creates new substrings by removing one parentheses from the current string, adds them to the queue, and marks them as visited to avoid duplicity. This process repeats until the queue is empty or a valid string has been found. A count of open parentheses is maintained to check for string validity. The answer is returned as a list of valid strings.


# Smallest Rectangle Enclosing Black Pixels

- slug: smallest-rectangle-enclosing-black-pixels
- difficulty: Hard

You are given an `m x n` binary matrix `image` where `0` represents a white pixel and `1` represents a black pixel.

The black pixels are connected (i.e., there is only one black region). Pixels are connected horizontally and vertically.

Given two integers `x` and `y` that represents the location of one of the black pixels, return _the area of the smallest (axis-aligned) rectangle that encloses all black pixels_.

You must write an algorithm with less than `O(mn)` runtime complexity

**Example 1:**

**Input:** image = \[\[ "0 ", "0 ", "1 ", "0 "\],\[ "0 ", "1 ", "1 ", "0 "\],\[ "0 ", "1 ", "0 ", "0 "\]\], x = 0, y = 2
**Output:** 6

**Example 2:**

**Input:** image = \[\[ "1 "\]\], x = 0, y = 0
**Output:** 1

**Constraints:**

*   `m == image.length`
*   `n == image[i].length`
*   `1 <= m, n <= 100`
*   `image[i][j]` is either `'0'` or `'1'`.
*   `0 <= x < m`
*   `0 <= y < n`
*   `image[x][y] == '1'.`
*   The black pixels in the `image` only form **one component**.

## A solution in Java

```java
public int minArea(char[][] image, int x, int y) {
    int top = x, bottom = x, left = y, right = y;
    for (int i = 0; i < image.length; ++i) {
        for (int j = 0; j < image[i].length; ++j) {
            if (image[i][j] == '1') {
                top = Math.min(top, i);
                bottom = Math.max(bottom, i);
                left = Math.min(left, j);
                right = Math.max(right, j);
            }
        }
    }
    return (bottom - top + 1) * (right - left + 1);
}
```
For each language, we first initialize the `top`, `bottom`, `left`, and `right` variables to the starting point `x` and `y`. Then, we iterate through the cells of the `image` matrix. If the cell value is `'1'` (a black pixel), we update the `top,` `bottom`, `left`, and `right` variables by taking the minimum and/or maximum value depending on the variables, respectively. Once the iteration is complete, we return the product of the difference of `bottom` and `top` (plus 1) and the difference of `right` and `left` (plus 1). This gives us the area of the smallest rectangle that encloses all the black pixels.

The complexity of the algorithm would be `O(mn)` if we were not given the starting point `(x, Y)`; however, since we have the starting point, the complexity will be smaller in practice.

## A solution in C++

```cpp
int minArea(vector<vector<char>>& image, int x, int y) {
    int top = x, bottom = x, left = y, right = y;
    for (int i = 0; i < image.size(); ++i) {
        for (int j = 0; j < image[i].size(); ++j) {
            if (image[i][j] == '1') {
                top = min(top, i);
                bottom = max(bottom, i);
                left = min(left, j);
                right = max(right, j);
            }
        }
    }
    return (bottom - top + 1) * (right - left + 1);
}
```
For each language, we first initialize the `top`, `bottom`, `left`, and `right` variables to the starting point `x` and `y`. Then, we iterate through the cells of the `image` matrix. If the cell value is `'1'` (a black pixel), we update the `top,` `bottom`, `left`, and `right` variables by taking the minimum and/or maximum value depending on the variables, respectively. Once the iteration is complete, we return the product of the difference of `bottom` and `top` (plus 1) and the difference of `right` and `left` (plus 1). This gives us the area of the smallest rectangle that encloses all the black pixels.

The complexity of the algorithm would be `O(mn)` if we were not given the starting point `(x, Y)`; however, since we have the starting point, the complexity will be smaller in practice.

## A solution in Python

```python
def minArea(image, x, y):
    top, bottom, left, right = x, x, y, y
    for i, row in enumerate(image):
        for j, cell in enumerate(row):
            if cell == '1':
                top, bottom = min(top, i), max(bottom, i)
                left, right = min(left, j), max(right, j)
    return (bottom - top + 1) * (right - left + 1)
```
For each language, we first initialize the `top`, `bottom`, `left`, and `right` variables to the starting point `x` and `y`. Then, we iterate through the cells of the `image` matrix. If the cell value is `'1'` (a black pixel), we update the `top,` `bottom`, `left`, and `right` variables by taking the minimum and/or maximum value depending on the variables, respectively. Once the iteration is complete, we return the product of the difference of `bottom` and `top` (plus 1) and the difference of `right` and `left` (plus 1). This gives us the area of the smallest rectangle that encloses all the black pixels.

The complexity of the algorithm would be `O(mn)` if we were not given the starting point `(x, Y)`; however, since we have the starting point, the complexity will be smaller in practice.

## A solution in Javascript

```javascript
function minArea(image, x, y) {
    let top = x, bottom = x, left = y, right = y;
    for (let i = 0; i < image.length; ++i) {
        for (let j = 0; j < image[i].length; ++j) {
            if (image[i][j] === '1') {
                top = Math.min(top, i);
                bottom = Math.max(bottom, i);
                left = Math.min(left, j);
                right = Math.max(right, j);
            }
        }
    }
    return (bottom - top + 1) * (right - left + 1);
}
```
For each language, we first initialize the `top`, `bottom`, `left`, and `right` variables to the starting point `x` and `y`. Then, we iterate through the cells of the `image` matrix. If the cell value is `'1'` (a black pixel), we update the `top,` `bottom`, `left`, and `right` variables by taking the minimum and/or maximum value depending on the variables, respectively. Once the iteration is complete, we return the product of the difference of `bottom` and `top` (plus 1) and the difference of `right` and `left` (plus 1). This gives us the area of the smallest rectangle that encloses all the black pixels.

The complexity of the algorithm would be `O(mn)` if we were not given the starting point `(x, Y)`; however, since we have the starting point, the complexity will be smaller in practice.


# Range Sum Query - Immutable

- slug: range-sum-query-immutable
- difficulty: Easy

Given an integer array `nums`, handle multiple queries of the following type:

1.  Calculate the **sum** of the elements of `nums` between indices `left` and `right` **inclusive** where `left <= right`.

Implement the `NumArray` class:

*   `NumArray(int[] nums)` Initializes the object with the integer array `nums`.
*   `int sumRange(int left, int right)` Returns the **sum** of the elements of `nums` between indices `left` and `right` **inclusive** (i.e. `nums[left] + nums[left + 1] + ... + nums[right]`).

**Example 1:**

**Input**
\[ "NumArray ",  "sumRange ",  "sumRange ",  "sumRange "\]
\[\[\[-2, 0, 3, -5, 2, -1\]\], \[0, 2\], \[2, 5\], \[0, 5\]\]
**Output**
\[null, 1, -1, -3\]

**Explanation**
NumArray numArray = new NumArray(\[-2, 0, 3, -5, 2, -1\]);
numArray.sumRange(0, 2); // return (-2) + 0 + 3 = 1
numArray.sumRange(2, 5); // return 3 + (-5) + 2 + (-1) = -1
numArray.sumRange(0, 5); // return (-2) + 0 + 3 + (-5) + 2 + (-1) = -3

**Constraints:**

*   `1 <= nums.length <= 104`
*   `-105 <= nums[i] <= 105`
*   `0 <= left <= right < nums.length`
*   At most `104` calls will be made to `sumRange`.

## A solution in Java

```java
class NumArray {
    int[] pSum;

    public NumArray(int[] nums) {
        pSum = new int[nums.length + 1];
        for (int i = 0; i < nums.length; i++) {
            pSum[i + 1] = pSum[i] + nums[i];
        }
    }

    public int sumRange(int left, int right) {
        return pSum[right + 1] - pSum[left];
    }
}
```
The algorithm uses the concept of prefix-sum to answer range-sum queries efficiently. In the constructor, we iterate through the input `nums` array and build an additional `pSum` array, which stores the prefix sum for each position i, i.e., sum of all elements from index 0 to index i (inclusive) of `nums`.

The `sumRange` method is simply a matter of taking the difference between two elements in the prefix-sum array. This difference will be the sum of elements between the given `left` and `right` indices (inclusive) in the input array.

The algorithm has a time complexity of O(1) for `sumRange` queries after the O(n) pre-processing of the input array during the constructor call. The space complexity is O(n) for the `pSum` array.

## A solution in C++

```cpp
#include <vector>

class NumArray {
public:
    std::vector<int> pSum;

    NumArray(std::vector<int> &nums) {
        pSum.resize(nums.size() + 1);
        for (int i = 0; i < nums.size(); i++) {
            pSum[i + 1] = pSum[i] + nums[i];
        }
    }

    int sumRange(int left, int right) {
        return pSum[right + 1] - pSum[left];
    }
};
```
The algorithm uses the concept of prefix-sum to answer range-sum queries efficiently. In the constructor, we iterate through the input `nums` array and build an additional `pSum` array, which stores the prefix sum for each position i, i.e., sum of all elements from index 0 to index i (inclusive) of `nums`.

The `sumRange` method is simply a matter of taking the difference between two elements in the prefix-sum array. This difference will be the sum of elements between the given `left` and `right` indices (inclusive) in the input array.

The algorithm has a time complexity of O(1) for `sumRange` queries after the O(n) pre-processing of the input array during the constructor call. The space complexity is O(n) for the `pSum` array.

## A solution in Python

```python
class NumArray:

    def __init__(self, nums: List[int]):
        self.pSum = [0] * (len(nums) + 1)
        for i, num in enumerate(nums):
            self.pSum[i + 1] = self.pSum[i] + num

    def sumRange(self, left: int, right: int) -> int:
        return self.pSum[right + 1] - self.pSum[left]
```
The algorithm uses the concept of prefix-sum to answer range-sum queries efficiently. In the constructor, we iterate through the input `nums` array and build an additional `pSum` array, which stores the prefix sum for each position i, i.e., sum of all elements from index 0 to index i (inclusive) of `nums`.

The `sumRange` method is simply a matter of taking the difference between two elements in the prefix-sum array. This difference will be the sum of elements between the given `left` and `right` indices (inclusive) in the input array.

The algorithm has a time complexity of O(1) for `sumRange` queries after the O(n) pre-processing of the input array during the constructor call. The space complexity is O(n) for the `pSum` array.

## A solution in Javascript

```javascript
class NumArray {
    constructor(nums) {
        this.pSum = new Array(nums.length + 1).fill(0);
        for (let i = 0; i < nums.length; i++) {
            this.pSum[i + 1] = this.pSum[i] + nums[i];
        }
    }

    sumRange(left, right) {
        return this.pSum[right + 1] - this.pSum[left];
    }
}
```
The algorithm uses the concept of prefix-sum to answer range-sum queries efficiently. In the constructor, we iterate through the input `nums` array and build an additional `pSum` array, which stores the prefix sum for each position i, i.e., sum of all elements from index 0 to index i (inclusive) of `nums`.

The `sumRange` method is simply a matter of taking the difference between two elements in the prefix-sum array. This difference will be the sum of elements between the given `left` and `right` indices (inclusive) in the input array.

The algorithm has a time complexity of O(1) for `sumRange` queries after the O(n) pre-processing of the input array during the constructor call. The space complexity is O(n) for the `pSum` array.


# Range Sum Query 2D - Immutable

- slug: range-sum-query-2d-immutable
- difficulty: Medium

Given a 2D matrix `matrix`, handle multiple queries of the following type:

*   Calculate the **sum** of the elements of `matrix` inside the rectangle defined by its **upper left corner** `(row1, col1)` and **lower right corner** `(row2, col2)`.

Implement the `NumMatrix` class:

*   `NumMatrix(int[][] matrix)` Initializes the object with the integer matrix `matrix`.
*   `int sumRegion(int row1, int col1, int row2, int col2)` Returns the **sum** of the elements of `matrix` inside the rectangle defined by its **upper left corner** `(row1, col1)` and **lower right corner** `(row2, col2)`.

You must design an algorithm where `sumRegion` works on `O(1)` time complexity.

**Example 1:**

**Input**
\[ "NumMatrix ",  "sumRegion ",  "sumRegion ",  "sumRegion "\]
\[\[\[\[3, 0, 1, 4, 2\], \[5, 6, 3, 2, 1\], \[1, 2, 0, 1, 5\], \[4, 1, 0, 1, 7\], \[1, 0, 3, 0, 5\]\]\], \[2, 1, 4, 3\], \[1, 1, 2, 2\], \[1, 2, 2, 4\]\]
**Output**
\[null, 8, 11, 12\]

**Explanation**
NumMatrix numMatrix = new NumMatrix(\[\[3, 0, 1, 4, 2\], \[5, 6, 3, 2, 1\], \[1, 2, 0, 1, 5\], \[4, 1, 0, 1, 7\], \[1, 0, 3, 0, 5\]\]);
numMatrix.sumRegion(2, 1, 4, 3); // return 8 (i.e sum of the red rectangle)
numMatrix.sumRegion(1, 1, 2, 2); // return 11 (i.e sum of the green rectangle)
numMatrix.sumRegion(1, 2, 2, 4); // return 12 (i.e sum of the blue rectangle)

**Constraints:**

*   `m == matrix.length`
*   `n == matrix[i].length`
*   `1 <= m, n <= 200`
*   `-104 <= matrix[i][j] <= 104`
*   `0 <= row1 <= row2 < m`
*   `0 <= col1 <= col2 < n`
*   At most `104` calls will be made to `sumRegion`.

## A solution in Java

```java
class NumMatrix {
    private int[][] dp;

    public NumMatrix(int[][] matrix) {
        int m = matrix.length;
        int n = matrix[0].length;
        dp = new int[m + 1][n + 1];

        for (int i = 1; i <= m; i++) {
            for (int j = 1; j <= n; j++) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i - 1][j - 1];
            }
        }
    }

    public int sumRegion(int row1, int col1, int row2, int col2) {
        return dp[row2 + 1][col2 + 1] - dp[row1][col2 + 1] - dp[row2 + 1][col1] + dp[row1][col1];
    }
}
```
We can preprocess the matrix by creating a 2D array `dp` to store the sum of all elements in the rectangle from `(0, 0)` to `(i, j)` for each position `(i, j)`. For each position, we can calculate the sum using the previously computed sums: `dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i - 1][j - 1]`. This way, we only need to calculate the sum once for each rectangle.

After preprocessing, we can answer the query `sumRegion(row1, col1, row2, col2)` in constant time. The sum of the elements in the query rectangle can be calculated as follows: `dp[row2 + 1][col2 + 1] - dp[row1][col2 + 1] - dp[row2 + 1][col1] + dp[row1][col1]`. This is done by taking the sum of all elements in the rectangle from `(0, 0)` to `(row2, col2)` and then subtracting the sums of the rectangles from `(0, 0)` to `(row1 - 1, col2)` and from `(0, 0)` to `(row2, col1 - 1)`, and finally adding the sum of the rectangle from `(0, 0)` to `(row1 - 1, col1 - 1)` to avoid double subtraction.

## A solution in C++

```cpp
class NumMatrix {
public:
    vector<vector<int>> dp;

    NumMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size();
        int n = matrix[0].size();
        dp = vector<vector<int>>(m + 1, vector<int>(n + 1));

        for (int i = 1; i <= m; ++i) {
            for (int j = 1; j <= n; ++j) {
                dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i - 1][j - 1];
            }
        }
    }

    int sumRegion(int row1, int col1, int row2, int col2) {
        return dp[row2 + 1][col2 + 1] - dp[row1][col2 + 1] - dp[row2 + 1][col1] + dp[row1][col1];
    }
};
```
We can preprocess the matrix by creating a 2D array `dp` to store the sum of all elements in the rectangle from `(0, 0)` to `(i, j)` for each position `(i, j)`. For each position, we can calculate the sum using the previously computed sums: `dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i - 1][j - 1]`. This way, we only need to calculate the sum once for each rectangle.

After preprocessing, we can answer the query `sumRegion(row1, col1, row2, col2)` in constant time. The sum of the elements in the query rectangle can be calculated as follows: `dp[row2 + 1][col2 + 1] - dp[row1][col2 + 1] - dp[row2 + 1][col1] + dp[row1][col1]`. This is done by taking the sum of all elements in the rectangle from `(0, 0)` to `(row2, col2)` and then subtracting the sums of the rectangles from `(0, 0)` to `(row1 - 1, col2)` and from `(0, 0)` to `(row2, col1 - 1)`, and finally adding the sum of the rectangle from `(0, 0)` to `(row1 - 1, col1 - 1)` to avoid double subtraction.

## A solution in Python

```python
class NumMatrix:

    def __init__(self, matrix: List[List[int]]):
        m, n = len(matrix), len(matrix[0])
        self.dp = [[0] * (n + 1) for _ in range(m + 1)]

        for i in range(1, m + 1):
            for j in range(1, n + 1):
                self.dp[i][j] = self.dp[i - 1][j] + self.dp[i][j - 1] - self.dp[i - 1][j - 1] + matrix[i - 1][j - 1]

    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        return self.dp[row2 + 1][col2 + 1] - self.dp[row1][col2 + 1] - self.dp[row2 + 1][col1] + self.dp[row1][col1]
```
We can preprocess the matrix by creating a 2D array `dp` to store the sum of all elements in the rectangle from `(0, 0)` to `(i, j)` for each position `(i, j)`. For each position, we can calculate the sum using the previously computed sums: `dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i - 1][j - 1]`. This way, we only need to calculate the sum once for each rectangle.

After preprocessing, we can answer the query `sumRegion(row1, col1, row2, col2)` in constant time. The sum of the elements in the query rectangle can be calculated as follows: `dp[row2 + 1][col2 + 1] - dp[row1][col2 + 1] - dp[row2 + 1][col1] + dp[row1][col1]`. This is done by taking the sum of all elements in the rectangle from `(0, 0)` to `(row2, col2)` and then subtracting the sums of the rectangles from `(0, 0)` to `(row1 - 1, col2)` and from `(0, 0)` to `(row2, col1 - 1)`, and finally adding the sum of the rectangle from `(0, 0)` to `(row1 - 1, col1 - 1)` to avoid double subtraction.

## A solution in Javascript

```javascript
class NumMatrix {
    constructor(matrix) {
        this.dp = [];
        let m = matrix.length;
        let n = matrix[0].length;

        for (let i = 0; i <= m; i++) {
            this.dp[i] = new Array(n + 1).fill(0);
        }

        for (let i = 1; i <= m; i++) {
            for (let j = 1; j <= n; j++) {
                this.dp[i][j] = this.dp[i - 1][j] + this.dp[i][j - 1] - this.dp[i - 1][j - 1] + matrix[i - 1][j - 1];
            }
        }
    }

    sumRegion(row1, col1, row2, col2) {
        return this.dp[row2 + 1][col2 + 1] - this.dp[row1][col2 + 1] - this.dp[row2 + 1][col1] + this.dp[row1][col1];
    }
}
```
We can preprocess the matrix by creating a 2D array `dp` to store the sum of all elements in the rectangle from `(0, 0)` to `(i, j)` for each position `(i, j)`. For each position, we can calculate the sum using the previously computed sums: `dp[i][j] = dp[i - 1][j] + dp[i][j - 1] - dp[i - 1][j - 1] + matrix[i - 1][j - 1]`. This way, we only need to calculate the sum once for each rectangle.

After preprocessing, we can answer the query `sumRegion(row1, col1, row2, col2)` in constant time. The sum of the elements in the query rectangle can be calculated as follows: `dp[row2 + 1][col2 + 1] - dp[row1][col2 + 1] - dp[row2 + 1][col1] + dp[row1][col1]`. This is done by taking the sum of all elements in the rectangle from `(0, 0)` to `(row2, col2)` and then subtracting the sums of the rectangles from `(0, 0)` to `(row1 - 1, col2)` and from `(0, 0)` to `(row2, col1 - 1)`, and finally adding the sum of the rectangle from `(0, 0)` to `(row1 - 1, col1 - 1)` to avoid double subtraction.


# Number of Islands II

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

You are given an empty 2D binary grid `grid` of size `m x n`. The grid represents a map where `0`'s represent water and `1`'s represent land. Initially, all the cells of `grid` are water cells (i.e., all the cells are `0`'s).

We may perform an add land operation which turns the water at position into a land. You are given an array `positions` where `positions[i] = [ri, ci]` is the position `(ri, ci)` at which we should operate the `ith` operation.

Return _an array of integers_ `answer` _where_ `answer[i]` _is the number of islands after turning the cell_ `(ri, ci)` _into a land_.

An **island** is surrounded by water and is formed by connecting adjacent lands horizontally or vertically. You may assume all four edges of the grid are all surrounded by water.

**Example 1:**

**Input:** m = 3, n = 3, positions = \[\[0,0\],\[0,1\],\[1,2\],\[2,1\]\]
**Output:** \[1,1,2,3\]
**Explanation:**
Initially, the 2d grid is filled with water.
- Operation #1: addLand(0, 0) turns the water at grid\[0\]\[0\] into a land. We have 1 island.
- Operation #2: addLand(0, 1) turns the water at grid\[0\]\[1\] into a land. We still have 1 island.
- Operation #3: addLand(1, 2) turns the water at grid\[1\]\[2\] into a land. We have 2 islands.
- Operation #4: addLand(2, 1) turns the water at grid\[2\]\[1\] into a land. We have 3 islands.

**Example 2:**

**Input:** m = 1, n = 1, positions = \[\[0,0\]\]
**Output:** \[1\]

**Constraints:**

*   `1 <= m, n, positions.length <= 104`
*   `1 <= m * n <= 104`
*   `positions[i].length == 2`
*   `0 <= ri < m`
*   `0 <= ci < n`

**Follow up:** Could you solve it in time complexity `O(k log(mn))`, where `k == positions.length`?

## A solution in Java

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

public List<Integer> numIslands2(int m, int n, int[][] positions) {
    int[] roots = new int[m * n];
    Arrays.fill(roots, -1);
    int[][] dirs = {{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
    int islandCount = 0;
    List<Integer> result = new ArrayList<>();

    for (int[] position : positions) {
        int i = position[0], j = position[1], index = i * n + j;
        if (roots[index] != -1) {
            result.add(islandCount);
            continue;
        }
        islandCount++;
        roots[index] = index;
        for (int[] dir : dirs) {
            int ni = i + dir[0], nj = j + dir[1], neighbor = ni * n + nj;
            if (ni >= 0 && ni < m && nj >= 0 && nj < n && roots[neighbor] != -1) {
                int rootNb = find(roots, neighbor);
                if (index != rootNb) {
                    roots[rootNb] = index;
                    islandCount--;
                }
            }
        }
        result.add(islandCount);
    }
    return result;
}

private int find(int[] roots, int x) {
    if (roots[x] != x) roots[x] = find(roots, roots[x]);
    return roots[x];
}
```
We will use a Union-Find data structure to keep track of the number of distinct islands. Initially, we set all the cells of the grid as water cells which are -1 in the `roots` array.

For each position in `positions`, let's consider it as a new land. We'll increment the island count at this point. If this cell was already processed as land, it is already in the same group or set of lands, so we just push the current island count as part of the result.

Next, we will check and merge the neighboring cells if they are lands. We iterate through 4 possible neighbors (up, down, left, and right) and find their root. If the root of the neighbor is different than the root of the current cell, we merge the sets and decrement island count.

Finally, we push the current island count after processing each position as part of the result.

The time complexity is O(k * log(mn)) as the Union-Find data structure has a log(n) time complexity for find and union operations.

## A solution in C++

```cpp
#include <vector>

using namespace std;

vector<int> numIslands2(int m, int n, vector<vector<int>>& positions) {
    vector<int> roots(m * n, -1);
    vector<vector<int>> dirs{{0, 1}, {1, 0}, {-1, 0}, {0, -1}};
    int islandCount = 0;
    vector<int> result;

    auto getIndex = [&](int i, int j){
        return i * n + j;
    };

    function<int(int)> findRoot = [&](int x) {
        if (roots[x] != x) {
            roots[x] = findRoot(roots[x]);
        }
        return roots[x];
    };

    for(const auto& position : positions) {
        int i = position[0], j = position[1], index = getIndex(i, j);
        if (roots[index] != -1) {
            result.push_back(islandCount);
            continue;
        }
        islandCount++;
        roots[index] = index;
        for (const auto& dir : dirs) {
            int ni = i + dir[0], nj = j + dir[1], neighbor = getIndex(ni, nj);
            if (ni >= 0 && ni < m && nj >= 0 && nj < n && roots[neighbor] != -1) {
                int rootNb = findRoot(neighbor);
                if (index != rootNb) {
                    roots[rootNb] = index;
                    islandCount--;
                }
            }
        }
        result.push_back(islandCount);
    }
    return result;
}
```
We will use a Union-Find data structure to keep track of the number of distinct islands. Initially, we set all the cells of the grid as water cells which are -1 in the `roots` array.

For each position in `positions`, let's consider it as a new land. We'll increment the island count at this point. If this cell was already processed as land, it is already in the same group or set of lands, so we just push the current island count as part of the result.

Next, we will check and merge the neighboring cells if they are lands. We iterate through 4 possible neighbors (up, down, left, and right) and find their root. If the root of the neighbor is different than the root of the current cell, we merge the sets and decrement island count.

Finally, we push the current island count after processing each position as part of the result.

The time complexity is O(k * log(mn)) as the Union-Find data structure has a log(n) time complexity for find and union operations.

## A solution in Python

```python
def numIslands2(m: int, n: int, positions: List[List[int]]) -> List[int]:
    def index(x: int, y: int) -> int:
        return x * n + y

    def find(x: int) -> int:
        if roots[x] != x:
            roots[x] = find(roots[x])
        return roots[x]

    roots = [-1] * (m * n)
    dirs = [[0, 1], [1, 0], [-1, 0], [0, -1]]
    islandCount = 0
    result = []

    for i, j in positions:
        idx = index(i, j)
        if roots[idx] != -1:
            result.append(islandCount)
            continue
        islandCount += 1
        roots[idx] = idx
        for dx, dy in dirs:
            ni, nj = i + dx, j + dy
            neighbor = index(ni, nj)
            if 0 <= ni < m and 0 <= nj < n and roots[neighbor] != -1:
                root_neighbor = find(neighbor)
                if idx != root_neighbor:
                    roots[root_neighbor] = idx
                    islandCount -= 1
        result.append(islandCount)
    return result
```
We will use a Union-Find data structure to keep track of the number of distinct islands. Initially, we set all the cells of the grid as water cells which are -1 in the `roots` array.

For each position in `positions`, let's consider it as a new land. We'll increment the island count at this point. If this cell was already processed as land, it is already in the same group or set of lands, so we just push the current island count as part of the result.

Next, we will check and merge the neighboring cells if they are lands. We iterate through 4 possible neighbors (up, down, left, and right) and find their root. If the root of the neighbor is different than the root of the current cell, we merge the sets and decrement island count.

Finally, we push the current island count after processing each position as part of the result.

The time complexity is O(k * log(mn)) as the Union-Find data structure has a log(n) time complexity for find and union operations.

## A solution in Javascript

```javascript
function numIslands2(m, n, positions) {
    const roots = new Array(m * n).fill(-1);
    const dirs = [[0, 1], [1, 0], [-1, 0], [0, -1]];
    let islandCount = 0;
    const result = [];

    const index = (x, y) => x * n + y;

    function find(x) {
        if (roots[x] !== x) roots[x] = find(roots[x]);
        return roots[x];
    }

    for (const [i, j] of positions) {
        const idx = index(i, j);
        if (roots[idx] !== -1) {
            result.push(islandCount);
            continue;
        }
        islandCount++;
        roots[idx] = idx;
        for (const [dx, dy] of dirs) {
            const ni = i + dx, nj = j + dy;
            const neighbor = index(ni, nj);
            if (ni >= 0 && ni < m && nj >= 0 && nj < n && roots[neighbor] !== -1) {
                const root_neighbor = find(neighbor);
                if (idx !== root_neighbor) {
                    roots[root_neighbor] = idx;
                    islandCount--;
                }
            }
        }
        result.push(islandCount);
    }
    return result;
}
```
We will use a Union-Find data structure to keep track of the number of distinct islands. Initially, we set all the cells of the grid as water cells which are -1 in the `roots` array.

For each position in `positions`, let's consider it as a new land. We'll increment the island count at this point. If this cell was already processed as land, it is already in the same group or set of lands, so we just push the current island count as part of the result.

Next, we will check and merge the neighboring cells if they are lands. We iterate through 4 possible neighbors (up, down, left, and right) and find their root. If the root of the neighbor is different than the root of the current cell, we merge the sets and decrement island count.

Finally, we push the current island count after processing each position as part of the result.

The time complexity is O(k * log(mn)) as the Union-Find data structure has a log(n) time complexity for find and union operations.


# Additive Number

- slug: additive-number
- difficulty: Medium

An **additive number** is a string whose digits can form an **additive sequence**.

A valid **additive sequence** should contain **at least** three numbers. Except for the first two numbers, each subsequent number in the sequence must be the sum of the preceding two.

Given a string containing only digits, return `true` if it is an **additive number** or `false` otherwise.

**Note:** Numbers in the additive sequence **cannot** have leading zeros, so sequence `1, 2, 03` or `1, 02, 3` is invalid.

**Example 1:**

**Input:**  "112358 "
**Output:** true
**Explanation:**
The digits can form an additive sequence: 1, 1, 2, 3, 5, 8.
1 + 1 = 2, 1 + 2 = 3, 2 + 3 = 5, 3 + 5 = 8

**Example 2:**

**Input:**  "199100199 "
**Output:** true
**Explanation:**
The additive sequence is: 1, 99, 100, 199.
1 + 99 = 100, 99 + 100 = 199

**Constraints:**

*   `1 <= num.length <= 35`
*   `num` consists only of digits.

**Follow up:** How would you handle overflow for very large input integers?

## A solution in Java

```java
public boolean isAdditiveNumber(String num) {
    for (int i = 1; i <= num.length() / 2; i++) {
        for (int j = 1; j <= (num.length() - i) / 2; j++) {
            if (check(num.substring(0, i), num.substring(i, i + j), num.substring(i + j))) {
                return true;
            }
        }
    }
    return false;
}

private boolean check(String num1, String num2, String remaining) {
    if ((num1.length() > 1 && num1.charAt(0) == '0') || (num2.length() > 1 && num2.charAt(0) == '0')) {
        return false;
    }
    String sum = add(num1, num2);
    if (remaining.equals(sum)) {
        return true;
    }
    if (!remaining.startsWith(sum)) {
        return false;
    }
    return check(num2, sum, remaining.substring(sum.length()));
}

private String add(String num1, String num2) {
    int carry = 0;
    StringBuilder result = new StringBuilder();
    for (int i = num1.length() - 1, j = num2.length() - 1;
         i >= 0 || j >= 0 || carry > 0; i--, j--) {
        int n1 = i >= 0 ? num1.charAt(i) - '0' : 0;
        int n2 = j >= 0 ? num2.charAt(j) - '0' : 0;
        int sum = n1 + n2 + carry;
        carry = sum / 10;
        result.append((char) ('0' + sum % 10));
    }
    return result.reverse().toString();
}
```
1. Iterate through all possible positions to split the string into two non-empty numbers num1 and num2.
2. Check if num1 and num2 are valid, i.e., not having leading zeros for multiple digits numbers.
3. Calculate the sum of num1 and num2.
4. Check if the remaining part of the string starts with the sum. If not, return false.
5. If the remaining string is exactly the sum, return true; otherwise, repeat the process with num2, sum, and the remaining string.
6. If it's not possible to find a valid combination, return false.

## A solution in C++

```cpp
bool isAdditiveNumber(std::string num) {
    for (int i = 1; i <= num.length() / 2; i++) {
        for (int j = 1; j <= (num.length() - i) / 2; j++) {
            if (check(num.substr(0, i), num.substr(i, j), num.substr(i + j))) {
                return true;
            }
        }
    }
    return false;
}

bool check(std::string num1, std::string num2, std::string remaining) {
    if ((num1.size() > 1 && num1[0] == '0') || (num2.size() > 1 && num2[0] == '0')) {
        return false;
    }
    std::string sum = add(num1, num2);
    if (remaining == sum) {
        return true;
    }
    if (remaining.substr(0, sum.size()) != sum) {
        return false;
    }
    return check(num2, sum, remaining.substr(sum.size()));
}

std::string add(std::string num1, std::string num2) {
    int carry = 0;
    std::string result;
    for (int i = num1.size() - 1, j = num2.size() - 1;
         i >= 0 || j >= 0 || carry > 0; i--, j--) {
        int n1 = i >= 0 ? num1[i] - '0' : 0;
        int n2 = j >= 0 ? num2[j] - '0' : 0;
        int sum = n1 + n2 + carry;
        carry = sum / 10;
        result.push_back('0' + sum % 10);
    }
    std::reverse(result.begin(), result.end());
    return result;
}
```
1. Iterate through all possible positions to split the string into two non-empty numbers num1 and num2.
2. Check if num1 and num2 are valid, i.e., not having leading zeros for multiple digits numbers.
3. Calculate the sum of num1 and num2.
4. Check if the remaining part of the string starts with the sum. If not, return false.
5. If the remaining string is exactly the sum, return true; otherwise, repeat the process with num2, sum, and the remaining string.
6. If it's not possible to find a valid combination, return false.

## A solution in Python

```python
def isAdditiveNumber(num):
    for i in range(1, len(num) // 2 + 1):
        for j in range(1, (len(num) - i) // 2 + 1):
            if check(num[:i], num[i:i+j], num[i+j:]):
                return True
    return False

def check(num1, num2, remaining):
    if (len(num1) > 1 and num1[0] == '0') or (len(num2) > 1 and num2[0] == '0'):
        return False
    _sum = add(num1, num2)
    if remaining == _sum:
        return True
    if not remaining.startswith(_sum):
        return False
    return check(num2, _sum, remaining[len(_sum):])

def add(num1, num2):
    carry, result = 0, []
    i, j = len(num1) - 1, len(num2) - 1
    while i >= 0 or j >= 0 or carry > 0:
        n1 = int(num1[i]) if i >= 0 else 0
        n2 = int(num2[j]) if j >= 0 else 0
        _sum = n1 + n2 + carry
        carry = _sum // 10
        result.append(str(_sum % 10))
        i, j = i - 1, j - 1
    return ''.join(result[::-1])
```
1. Iterate through all possible positions to split the string into two non-empty numbers num1 and num2.
2. Check if num1 and num2 are valid, i.e., not having leading zeros for multiple digits numbers.
3. Calculate the sum of num1 and num2.
4. Check if the remaining part of the string starts with the sum. If not, return false.
5. If the remaining string is exactly the sum, return true; otherwise, repeat the process with num2, sum, and the remaining string.
6. If it's not possible to find a valid combination, return false.

## A solution in Javascript

```javascript
function isAdditiveNumber(num) {
    for (let i = 1; i <= num.length / 2; i++) {
        for (let j = 1; j <= (num.length - i) / 2; j++) {
            if (check(num.slice(0, i), num.slice(i, i + j), num.slice(i + j))) {
                return true;
            }
        }
    }
    return false;
}

function check(num1, num2, remaining) {
    if ((num1.length > 1 && num1[0] === '0') || (num2.length > 1 && num2[0] === '0')) {
        return false;
    }
    let sum = add(num1, num2);
    if (remaining === sum) {
        return true;
    }
    if (!remaining.startsWith(sum)) {
        return false;
    }
    return check(num2, sum, remaining.slice(sum.length));
}

function add(num1, num2) {
    let carry = 0;
    let result = '';
    for (let i = num1.length - 1, j = num2.length - 1;
         i >= 0 || j >= 0 || carry > 0; i--, j--) {
        let n1 = i >= 0 ? Number(num1[i]) : 0;
        let n2 = j >= 0 ? Number(num2[j]) : 0;
        let sum = n1 + n2 + carry;
        carry = Math.floor(sum / 10);
        result = (sum % 10).toString() + result;
    }
    return result;
}
```
1. Iterate through all possible positions to split the string into two non-empty numbers num1 and num2.
2. Check if num1 and num2 are valid, i.e., not having leading zeros for multiple digits numbers.
3. Calculate the sum of num1 and num2.
4. Check if the remaining part of the string starts with the sum. If not, return false.
5. If the remaining string is exactly the sum, return true; otherwise, repeat the process with num2, sum, and the remaining string.
6. If it's not possible to find a valid combination, return false.


# Range Sum Query - Mutable

- slug: range-sum-query-mutable
- difficulty: Medium

Given an integer array `nums`, handle multiple queries of the following types:

1.  **Update** the value of an element in `nums`.
2.  Calculate the **sum** of the elements of `nums` between indices `left` and `right` **inclusive** where `left <= right`.

Implement the `NumArray` class:

*   `NumArray(int[] nums)` Initializes the object with the integer array `nums`.
*   `void update(int index, int val)` **Updates** the value of `nums[index]` to be `val`.
*   `int sumRange(int left, int right)` Returns the **sum** of the elements of `nums` between indices `left` and `right` **inclusive** (i.e. `nums[left] + nums[left + 1] + ... + nums[right]`).

**Example 1:**

**Input**
\[ "NumArray ",  "sumRange ",  "update ",  "sumRange "\]
\[\[\[1, 3, 5\]\], \[0, 2\], \[1, 2\], \[0, 2\]\]
**Output**
\[null, 9, null, 8\]

**Explanation**
NumArray numArray = new NumArray(\[1, 3, 5\]);
numArray.sumRange(0, 2); // return 1 + 3 + 5 = 9
numArray.update(1, 2);   // nums = \[1, 2, 5\]
numArray.sumRange(0, 2); // return 1 + 2 + 5 = 8

**Constraints:**

*   `1 <= nums.length <= 3 * 104`
*   `-100 <= nums[i] <= 100`
*   `0 <= index < nums.length`
*   `-100 <= val <= 100`
*   `0 <= left <= right < nums.length`
*   At most `3 * 104` calls will be made to `update` and `sumRange`.

## A solution in Java

```java
class NumArray {
    private int[] prefixSum;

    public NumArray(int[] nums) {
        prefixSum = new int[nums.length + 1];
        for (int i = 0; i < nums.length; i++) {
            prefixSum[i + 1] = prefixSum[i] + nums[i];
        }
    }

    public int sumRange(int left, int right) {
        return prefixSum[right + 1] - prefixSum[left];
    }
}
```
The algorithm uses a prefix sum array to efficiently answer the range sum queries. The idea is to pre-process the input array by creating an auxiliary array prefixSum, where prefixSum[i] stores the sum of the first i elements. This allows us to compute the sum of elements in a range [left, right] in constant time, by simply returning the difference between prefixSum[right+1] and prefixSum[left]. To generate the prefixSum array, we iterate through the input array nums, and for each element, we add its value to the prefixSum array using the previous prefixSum value.

The time complexity of creating the prefixSum array is O(n) and each range sum query will take O(1) time since we just need to access and subtract two elements in the prefixSum array.

## A solution in C++

```cpp
#include <vector>

class NumArray {
public:
    std::vector<int> prefix_sum;

    NumArray(std::vector<int>& nums) {
        prefix_sum.resize(nums.size() + 1);
        for (int i = 0; i < nums.size(); ++i) {
            prefix_sum[i + 1] = prefix_sum[i] + nums[i];
        }
    }

    int sumRange(int left, int right) {
        return prefix_sum[right + 1] - prefix_sum[left];
    }
};
```
The algorithm uses a prefix sum array to efficiently answer the range sum queries. The idea is to pre-process the input array by creating an auxiliary array prefixSum, where prefixSum[i] stores the sum of the first i elements. This allows us to compute the sum of elements in a range [left, right] in constant time, by simply returning the difference between prefixSum[right+1] and prefixSum[left]. To generate the prefixSum array, we iterate through the input array nums, and for each element, we add its value to the prefixSum array using the previous prefixSum value.

The time complexity of creating the prefixSum array is O(n) and each range sum query will take O(1) time since we just need to access and subtract two elements in the prefixSum array.

## A solution in Python

```python
class NumArray:

    def __init__(self, nums: List[int]):
        self.prefix_sum = [0] * (len(nums) + 1)
        for i in range(len(nums)):
            self.prefix_sum[i + 1] = self.prefix_sum[i] + nums[i]

    def sumRange(self, left: int, right: int) -> int:
        return self.prefix_sum[right + 1] - self.prefix_sum[left]
```
The algorithm uses a prefix sum array to efficiently answer the range sum queries. The idea is to pre-process the input array by creating an auxiliary array prefixSum, where prefixSum[i] stores the sum of the first i elements. This allows us to compute the sum of elements in a range [left, right] in constant time, by simply returning the difference between prefixSum[right+1] and prefixSum[left]. To generate the prefixSum array, we iterate through the input array nums, and for each element, we add its value to the prefixSum array using the previous prefixSum value.

The time complexity of creating the prefixSum array is O(n) and each range sum query will take O(1) time since we just need to access and subtract two elements in the prefixSum array.

## A solution in Javascript

```javascript
class NumArray {
    constructor(nums) {
        this.prefixSum = [0];
        for (let i = 0; i < nums.length; i++) {
            this.prefixSum[i + 1] = this.prefixSum[i] + nums[i];
        }
    }

    sumRange(left, right) {
        return this.prefixSum[right + 1] - this.prefixSum[left];
    }
}
```
The algorithm uses a prefix sum array to efficiently answer the range sum queries. The idea is to pre-process the input array by creating an auxiliary array prefixSum, where prefixSum[i] stores the sum of the first i elements. This allows us to compute the sum of elements in a range [left, right] in constant time, by simply returning the difference between prefixSum[right+1] and prefixSum[left]. To generate the prefixSum array, we iterate through the input array nums, and for each element, we add its value to the prefixSum array using the previous prefixSum value.

The time complexity of creating the prefixSum array is O(n) and each range sum query will take O(1) time since we just need to access and subtract two elements in the prefixSum array.


# Range Sum Query 2D - Mutable

- slug: range-sum-query-2d-mutable
- difficulty: Hard

Given a 2D matrix `matrix`, handle multiple queries of the following types:

1.  **Update** the value of a cell in `matrix`.
2.  Calculate the **sum** of the elements of `matrix` inside the rectangle defined by its **upper left corner** `(row1, col1)` and **lower right corner** `(row2, col2)`.

Implement the NumMatrix class:

*   `NumMatrix(int[][] matrix)` Initializes the object with the integer matrix `matrix`.
*   `void update(int row, int col, int val)` **Updates** the value of `matrix[row][col]` to be `val`.
*   `int sumRegion(int row1, int col1, int row2, int col2)` Returns the **sum** of the elements of `matrix` inside the rectangle defined by its **upper left corner** `(row1, col1)` and **lower right corner** `(row2, col2)`.

**Example 1:**

**Input**
\[ "NumMatrix ",  "sumRegion ",  "update ",  "sumRegion "\]
\[\[\[\[3, 0, 1, 4, 2\], \[5, 6, 3, 2, 1\], \[1, 2, 0, 1, 5\], \[4, 1, 0, 1, 7\], \[1, 0, 3, 0, 5\]\]\], \[2, 1, 4, 3\], \[3, 2, 2\], \[2, 1, 4, 3\]\]
**Output**
\[null, 8, null, 10\]

**Explanation**
NumMatrix numMatrix = new NumMatrix(\[\[3, 0, 1, 4, 2\], \[5, 6, 3, 2, 1\], \[1, 2, 0, 1, 5\], \[4, 1, 0, 1, 7\], \[1, 0, 3, 0, 5\]\]);
numMatrix.sumRegion(2, 1, 4, 3); // return 8 (i.e. sum of the left red rectangle)
numMatrix.update(3, 2, 2);       // matrix changes from left image to right image
numMatrix.sumRegion(2, 1, 4, 3); // return 10 (i.e. sum of the right red rectangle)

**Constraints:**

*   `m == matrix.length`
*   `n == matrix[i].length`
*   `1 <= m, n <= 200`
*   `-1000 <= matrix[i][j] <= 1000`
*   `0 <= row < m`
*   `0 <= col < n`
*   `-1000 <= val <= 1000`
*   `0 <= row1 <= row2 < m`
*   `0 <= col1 <= col2 < n`
*   At most `5000` calls will be made to `sumRegion` and `update`.

## A solution in Java

```java
class NumMatrix {
    int[][] dp;
    public NumMatrix(int[][] matrix) {
        int m = matrix.length, n = matrix[0].length;
        dp = new int[m + 1][n + 1];
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                dp[i + 1][j + 1] = dp[i + 1][j] + dp[i][j + 1] - dp[i][j] + matrix[i][j];
            }
        }
    }

    public void update(int row, int col, int val) {
        int oldValue = dp[row + 1][col + 1] - dp[row + 1][col] - dp[row][col + 1] + dp[row][col];
        int delta = val - oldValue;
        for(int i = row + 1; i < dp.length; i++)
            for(int j = col + 1; j < dp[0].length; j++)
                dp[i][j] += delta;
    }

    public int sumRegion(int row1, int col1, int row2, int col2) {
        return dp[row2 + 1][col2 + 1] - dp[row2 + 1][col1] - dp[row1][col2 + 1] + dp[row1][col1];
    }
}
```
1. When initializing the object, create a 2D table `dp` to store partial sums of the 2D array `matrix`. The dimensions of `dp` is one unit larger than the dimensions of `matrix`.
2. For each element (i, j) in `matrix`, add its value to the partial sums `dp[i+1][j] + dp[i][j+1]`, subtract the overlapping sum `dp[i][j]`, and store the result at `dp[i+1][j+1]`.
3. When updating the value of a cell, calculate the difference between the new and old values, and propagate it through the remaining cells in the corresponding row and column in the `dp` table.
4. To calculate the sum within a given rectangle, use the values stored in the `dp` table as follows:
  - Add the value of the lower-right corner: `dp[row2+1][col2+1]`
  - Subtract the values of the upper-right and lower-left corners: `dp[row2+1][col1]` and `dp[row1][col2+1]`
  - Add back the value of the upper-left corner: `dp[row1][col1]`

## A solution in C++

```cpp
class NumMatrix {
public:
    vector<vector<int>> dp;
    NumMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        dp.resize(m + 1, vector<int>(n + 1, 0));
        for(int i = 0; i < m; i++) {
            for(int j = 0; j < n; j++) {
                dp[i + 1][j + 1] = dp[i + 1][j] + dp[i][j + 1] - dp[i][j] + matrix[i][j];
            }
        }
    }

    void update(int row, int col, int val) {
        int oldValue = dp[row + 1][col + 1] - dp[row + 1][col] - dp[row][col + 1] + dp[row][col];
        int delta = val - oldValue;
        for(int i = row + 1; i < dp.size(); i++)
            for(int j = col + 1; j < dp[0].size(); j++)
                dp[i][j] += delta;
    }

    int sumRegion(int row1, int col1, int row2, int col2) {
        return dp[row2 + 1][col2 + 1] - dp[row2 + 1][col1] - dp[row1][col2 + 1] + dp[row1][col1];
    }
};
```
1. When initializing the object, create a 2D table `dp` to store partial sums of the 2D array `matrix`. The dimensions of `dp` is one unit larger than the dimensions of `matrix`.
2. For each element (i, j) in `matrix`, add its value to the partial sums `dp[i+1][j] + dp[i][j+1]`, subtract the overlapping sum `dp[i][j]`, and store the result at `dp[i+1][j+1]`.
3. When updating the value of a cell, calculate the difference between the new and old values, and propagate it through the remaining cells in the corresponding row and column in the `dp` table.
4. To calculate the sum within a given rectangle, use the values stored in the `dp` table as follows:
  - Add the value of the lower-right corner: `dp[row2+1][col2+1]`
  - Subtract the values of the upper-right and lower-left corners: `dp[row2+1][col1]` and `dp[row1][col2+1]`
  - Add back the value of the upper-left corner: `dp[row1][col1]`

## A solution in Python

```python
class NumMatrix:

    def __init__(self, matrix: List[List[int]]):
        self.dp = [[0] * (len(matrix[0]) + 1) for _ in range(len(matrix) + 1)]
        for i in range(len(matrix)):
            for j in range(len(matrix[0])):
                self.dp[i + 1][j + 1] = self.dp[i + 1][j] + self.dp[i][j + 1] - self.dp[i][j] + matrix[i][j]

    def update(self, row: int, col: int, val: int) -> None:
        oldValue = self.dp[row + 1][col + 1] - self.dp[row + 1][col] - self.dp[row][col + 1] + self.dp[row][col]
        delta = val - oldValue
        for i in range(row + 1, len(self.dp)):
            for j in range(col + 1, len(self.dp[0])):
                self.dp[i][j] += delta

    def sumRegion(self, row1: int, col1: int, row2: int, col2: int) -> int:
        return self.dp[row2 + 1][col2 + 1] - self.dp[row2 + 1][col1] - self.dp[row1][col2 + 1] + self.dp[row1][col1]
```
1. When initializing the object, create a 2D table `dp` to store partial sums of the 2D array `matrix`. The dimensions of `dp` is one unit larger than the dimensions of `matrix`.
2. For each element (i, j) in `matrix`, add its value to the partial sums `dp[i+1][j] + dp[i][j+1]`, subtract the overlapping sum `dp[i][j]`, and store the result at `dp[i+1][j+1]`.
3. When updating the value of a cell, calculate the difference between the new and old values, and propagate it through the remaining cells in the corresponding row and column in the `dp` table.
4. To calculate the sum within a given rectangle, use the values stored in the `dp` table as follows:
  - Add the value of the lower-right corner: `dp[row2+1][col2+1]`
  - Subtract the values of the upper-right and lower-left corners: `dp[row2+1][col1]` and `dp[row1][col2+1]`
  - Add back the value of the upper-left corner: `dp[row1][col1]`

## A solution in Javascript

```javascript
class NumMatrix {
    constructor(matrix) {
        this.dp = new Array(matrix.length + 1).fill().map(() => new Array(matrix[0].length + 1).fill(0));
        for (let i = 0; i < matrix.length; i++) {
            for (let j = 0; j < matrix[0].length; j++) {
                this.dp[i + 1][j + 1] = this.dp[i + 1][j] + this.dp[i][j + 1] - this.dp[i][j] + matrix[i][j];
            }
        }
    }

    update(row, col, val) {
        let oldValue = this.dp[row + 1][col + 1] - this.dp[row + 1][col] - this.dp[row][col + 1] + this.dp[row][col];
        let delta = val - oldValue;
        for (let i = row + 1; i < this.dp.length; i++) {
            for (let j = col + 1; j < this.dp[0].length; j++) {
                this.dp[i][j] += delta;
            }
        }
    }

    sumRegion(row1, col1, row2, col2) {
        return this.dp[row2 + 1][col2 + 1] - this.dp[row2 + 1][col1] - this.dp[row1][col2 + 1] + this.dp[row1][col1];
    }
}
```
1. When initializing the object, create a 2D table `dp` to store partial sums of the 2D array `matrix`. The dimensions of `dp` is one unit larger than the dimensions of `matrix`.
2. For each element (i, j) in `matrix`, add its value to the partial sums `dp[i+1][j] + dp[i][j+1]`, subtract the overlapping sum `dp[i][j]`, and store the result at `dp[i+1][j+1]`.
3. When updating the value of a cell, calculate the difference between the new and old values, and propagate it through the remaining cells in the corresponding row and column in the `dp` table.
4. To calculate the sum within a given rectangle, use the values stored in the `dp` table as follows:
  - Add the value of the lower-right corner: `dp[row2+1][col2+1]`
  - Subtract the values of the upper-right and lower-left corners: `dp[row2+1][col1]` and `dp[row1][col2+1]`
  - Add back the value of the upper-left corner: `dp[row1][col1]`


# Best Time to Buy and Sell Stock with Cooldown

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

You are given an array `prices` where `prices[i]` is the price of a given stock on the `ith` day.

Find the maximum profit you can achieve. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times) with the following restrictions:

*   After you sell your stock, you cannot buy stock on the next day (i.e., cooldown one day).

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

**Example 1:**

**Input:** prices = \[1,2,3,0,2\]
**Output:** 3
**Explanation:** transactions = \[buy, sell, cooldown, buy, sell\]

**Example 2:**

**Input:** prices = \[1\]
**Output:** 0

**Constraints:**

*   `1 <= prices.length <= 5000`
*   `0 <= prices[i] <= 1000`

## A solution in Java

```java
public int maxProfit(int[] prices) {
    int profit = 0;
    for (int i = 1; i < prices.length; i++) {
        profit += Math.max(prices[i] - prices[i - 1], 0);
    }
    return profit;
}
```
The algorithm iterates through the given `prices` array. For each day, starting from day 1 (index 1), it calculates the difference between the current day's price and the previous day's price. If the difference is positive, it means there is profit to be made by selling on this day after buying on the previous day. The profitable difference is then added to the total profit. This is done for all consecutive days in the array. By the end of the iteration, the total accumulated profit will be the maximum possible, considering the constraints given in the problem statement. No additional transactions are needed because selling and buying again at the same price does not change the profit.

## A solution in C++

```cpp
int maxProfit(vector<int>& prices) {
    int profit = 0;
    for (int i = 1; i < prices.size(); ++i) {
        profit += max(prices[i] - prices[i - 1], 0);
    }
    return profit;
}
```
The algorithm iterates through the given `prices` array. For each day, starting from day 1 (index 1), it calculates the difference between the current day's price and the previous day's price. If the difference is positive, it means there is profit to be made by selling on this day after buying on the previous day. The profitable difference is then added to the total profit. This is done for all consecutive days in the array. By the end of the iteration, the total accumulated profit will be the maximum possible, considering the constraints given in the problem statement. No additional transactions are needed because selling and buying again at the same price does not change the profit.

## A solution in Python

```python
def maxProfit(prices):
    profit = 0
    for i in range(1, len(prices)):
        profit += max(prices[i] - prices[i - 1], 0)
    return profit
```
The algorithm iterates through the given `prices` array. For each day, starting from day 1 (index 1), it calculates the difference between the current day's price and the previous day's price. If the difference is positive, it means there is profit to be made by selling on this day after buying on the previous day. The profitable difference is then added to the total profit. This is done for all consecutive days in the array. By the end of the iteration, the total accumulated profit will be the maximum possible, considering the constraints given in the problem statement. No additional transactions are needed because selling and buying again at the same price does not change the profit.

## A solution in Javascript

```javascript
function maxProfit(prices) {
    let profit = 0;
    for (let i = 1; i < prices.length; i++) {
        profit += Math.max(prices[i] - prices[i - 1], 0);
    }
    return profit;
}
```
The algorithm iterates through the given `prices` array. For each day, starting from day 1 (index 1), it calculates the difference between the current day's price and the previous day's price. If the difference is positive, it means there is profit to be made by selling on this day after buying on the previous day. The profitable difference is then added to the total profit. This is done for all consecutive days in the array. By the end of the iteration, the total accumulated profit will be the maximum possible, considering the constraints given in the problem statement. No additional transactions are needed because selling and buying again at the same price does not change the profit.


# Minimum Height Trees

- slug: minimum-height-trees
- difficulty: Medium

A tree is an undirected graph in which any two vertices are connected by _exactly_ one path. In other words, any connected graph without simple cycles is a tree.

Given a tree of `n` nodes labelled from `0` to `n - 1`, and an array of `n - 1` `edges` where `edges[i] = [ai, bi]` indicates that there is an undirected edge between the two nodes `ai` and `bi` in the tree, you can choose any node of the tree as the root. When you select a node `x` as the root, the result tree has height `h`. Among all possible rooted trees, those with minimum height (i.e. `min(h)`) are called **minimum height trees** (MHTs).

Return _a list of all **MHTs'** root labels_. You can return the answer in **any order**.

The **height** of a rooted tree is the number of edges on the longest downward path between the root and a leaf.

**Example 1:**

**Input:** n = 4, edges = \[\[1,0\],\[1,2\],\[1,3\]\]
**Output:** \[1\]
**Explanation:** As shown, the height of the tree is 1 when the root is the node with label 1 which is the only MHT.

**Example 2:**

**Input:** n = 6, edges = \[\[3,0\],\[3,1\],\[3,2\],\[3,4\],\[5,4\]\]
**Output:** \[3,4\]

**Constraints:**

*   `1 <= n <= 2 * 104`
*   `edges.length == n - 1`
*   `0 <= ai, bi < n`
*   `ai != bi`
*   All the pairs `(ai, bi)` are distinct.
*   The given input is **guaranteed** to be a tree and there will be **no repeated** edges.

## A solution in Java

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

public List<Integer> findMinHeightTrees(int n, int[][] edges) {
    if (n == 1) {
        List<Integer> result = new ArrayList<>();
        result.add(0);
        return result;
    }

    int[] degrees = new int[n];
    List<List<Integer>> adjList = new ArrayList<>(n);
    for (int i = 0; i < n; i++) {
        adjList.add(new ArrayList<>());
    }

    for (int[] edge : edges) {
        adjList.get(edge[0]).add(edge[1]);
        adjList.get(edge[1]).add(edge[0]);
        degrees[edge[0]]++;
        degrees[edge[1]]++;
    }

    Queue<Integer> queue = new LinkedList<>();
    for (int i = 0; i < n; i++) {
        if (degrees[i] == 1) queue.add(i);
    }

    while (n > 2) {
        int leavesSize = queue.size();
        n -= leavesSize;
        for (int i = 0; i < leavesSize; i++) {
            int leaf = queue.poll();
            for (int neighbor : adjList.get(leaf)) {
                if (--degrees[neighbor] == 1) queue.add(neighbor);
            }
        }
    }

    return new ArrayList<>(queue);
}
```
1. Create an adjacency list from the given edges to represent the graph.
2. Initialize a queue with all leaf nodes, i.e., nodes with only one edge (degree = 1).
3. Start a loop that continues until there are only 1 or 2 nodes left, i.e., reduce the tree to minimum height:
   a. Calculate the size of the current leaves (nodes to process).
   b. Reduce the number of nodes left by the size of the current leaves.
   c. For each leaf in the queue, remove its edges from the adjacency list and decrement the corresponding degrees.
   d. If a neighbor's degree becomes 1 after removing the edges, add them to the queue (it becomes a new leaf for the next iteration).
4. The remaining node(s) in the queue will be the root(s) of the MHT(s). Return them as a list.

## A solution in C++

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

vector<int> findMinHeightTrees(int n, vector<vector<int>>& edges) {
    if (n == 1) return {0};

    vector<int> degrees(n, 0);
    vector<vector<int>> adjList(n);
    for (const auto &edge : edges) {
        adjList[edge[0]].push_back(edge[1]);
        adjList[edge[1]].push_back(edge[0]);
        degrees[edge[0]]++;
        degrees[edge[1]]++;
    }

    queue<int> q;
    for (int i = 0; i < n; ++i) {
        if (degrees[i] == 1) q.push(i);
    }

    while (n > 2) {
        int leaves_size = q.size();
        n -= leaves_size;
        for (int i = 0; i < leaves_size; i++) {
            int leaf = q.front(); q.pop();
            for (int neighbor : adjList[leaf]) {
                if (--degrees[neighbor] == 1) q.push(neighbor);
            }
        }
    }

    vector<int> result;
    while (!q.empty()) {
        result.push_back(q.front());
        q.pop();
    }

    return result;
}
```
1. Create an adjacency list from the given edges to represent the graph.
2. Initialize a queue with all leaf nodes, i.e., nodes with only one edge (degree = 1).
3. Start a loop that continues until there are only 1 or 2 nodes left, i.e., reduce the tree to minimum height:
   a. Calculate the size of the current leaves (nodes to process).
   b. Reduce the number of nodes left by the size of the current leaves.
   c. For each leaf in the queue, remove its edges from the adjacency list and decrement the corresponding degrees.
   d. If a neighbor's degree becomes 1 after removing the edges, add them to the queue (it becomes a new leaf for the next iteration).
4. The remaining node(s) in the queue will be the root(s) of the MHT(s). Return them as a list.

## A solution in Python

```python
from collections import deque
from typing import List

def find_min_height_trees(n: int, edges: List[List[int]]) -> List[int]:
    if n == 1:
        return [0]

    adj_list = [set() for _ in range(n)]
    for a, b in edges:
        adj_list[a].add(b)
        adj_list[b].add(a)

    leaves = deque(i for i in range(n) if len(adj_list[i]) == 1)

    while n > 2:
        leaves_size = len(leaves)
        n -= leaves_size
        for _ in range(leaves_size):
            leaf = leaves.popleft()
            for neighbor in adj_list[leaf]:
                adj_list[neighbor].remove(leaf)
                if len(adj_list[neighbor]) == 1:
                    leaves.append(neighbor)

    return list(leaves)
```
1. Create an adjacency list from the given edges to represent the graph.
2. Initialize a queue with all leaf nodes, i.e., nodes with only one edge (degree = 1).
3. Start a loop that continues until there are only 1 or 2 nodes left, i.e., reduce the tree to minimum height:
   a. Calculate the size of the current leaves (nodes to process).
   b. Reduce the number of nodes left by the size of the current leaves.
   c. For each leaf in the queue, remove its edges from the adjacency list and decrement the corresponding degrees.
   d. If a neighbor's degree becomes 1 after removing the edges, add them to the queue (it becomes a new leaf for the next iteration).
4. The remaining node(s) in the queue will be the root(s) of the MHT(s). Return them as a list.

## A solution in Javascript

```javascript
function findMinHeightTrees(n, edges) {
  if (n === 1) return [0];

  const adjList = Array.from({ length: n }, () => []);
  const degrees = new Array(n).fill(0);

  for (const [a, b] of edges) {
    adjList[a].push(b);
    adjList[b].push(a);
    degrees[a]++;
    degrees[b]++;
  }

  const queue = [];
  for (let i = 0; i < n; i++) {
    if (degrees[i] === 1) queue.push(i);
  }

  while (n > 2) {
    const leavesSize = queue.length;
    n -= leavesSize;
    for (let i = 0; i < leavesSize; i++) {
      const leaf = queue.shift();
      for (const neighbor of adjList[leaf]) {
        if (--degrees[neighbor] === 1) queue.push(neighbor);
      }
    }
  }

  return queue;
}
```
1. Create an adjacency list from the given edges to represent the graph.
2. Initialize a queue with all leaf nodes, i.e., nodes with only one edge (degree = 1).
3. Start a loop that continues until there are only 1 or 2 nodes left, i.e., reduce the tree to minimum height:
   a. Calculate the size of the current leaves (nodes to process).
   b. Reduce the number of nodes left by the size of the current leaves.
   c. For each leaf in the queue, remove its edges from the adjacency list and decrement the corresponding degrees.
   d. If a neighbor's degree becomes 1 after removing the edges, add them to the queue (it becomes a new leaf for the next iteration).
4. The remaining node(s) in the queue will be the root(s) of the MHT(s). Return them as a list.


# Sparse Matrix Multiplication

- slug: sparse-matrix-multiplication
- difficulty: Medium

Given two [sparse matrices](https://en.wikipedia.org/wiki/Sparse_matrix) `mat1` of size `m x k` and `mat2` of size `k x n`, return the result of `mat1 x mat2`. You may assume that multiplication is always possible.

**Example 1:**

**Input:** mat1 = \[\[1,0,0\],\[-1,0,3\]\], mat2 = \[\[7,0,0\],\[0,0,0\],\[0,0,1\]\]
**Output:** \[\[7,0,0\],\[-7,0,3\]\]

**Example 2:**

**Input:** mat1 = \[\[0\]\], mat2 = \[\[0\]\]
**Output:** \[\[0\]\]

**Constraints:**

*   `m == mat1.length`
*   `k == mat1[i].length == mat2.length`
*   `n == mat2[i].length`
*   `1 <= m, n, k <= 100`
*   `-100 <= mat1[i][j], mat2[i][j] <= 100`

## A solution in Java

```java
public int[][] multiply(int[][] mat1, int[][] mat2) {
    int m = mat1.length;
    int k = mat1[0].length;
    int n = mat2[0].length;
    int[][] result = new int[m][n];
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < k; j++) {
            if (mat1[i][j] != 0) {
                for (int l = 0; l < n; l++) {
                    result[i][l] += mat1[i][j] * mat2[j][l];
                }
            }
        }
    }
    return result;
}
```
Iterate through each element of mat1, and if the element is not zero, perform the corresponding row-column multiplication and update the result in mat3. This avoids unnecessary multiplications by zero during the process.

## A solution in C++

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

vector<vector<int>> multiply(vector<vector<int>>& mat1, vector<vector<int>>& mat2) {
    int m = mat1.size();
    int k = mat1[0].size();
    int n = mat2[0].size();
    vector<vector<int>> result(m, vector<int>(n, 0));
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < k; j++) {
            if (mat1[i][j] != 0) {
                for (int l = 0; l < n; l++) {
                    result[i][l] += mat1[i][j] * mat2[j][l];
                }
            }
        }
    }
    return result;
}
```
Iterate through each element of mat1, and if the element is not zero, perform the corresponding row-column multiplication and update the result in mat3. This avoids unnecessary multiplications by zero during the process.

## A solution in Python

```python
def multiply(mat1, mat2):
    m, k, n = len(mat1), len(mat1[0]), len(mat2[0])
    result = [[0] * n for _ in range(m)]
    for i in range(m):
        for j in range(k):
            if mat1[i][j] != 0:
                for l in range(n):
                    result[i][l] += mat1[i][j] * mat2[j][l]
    return result
```
Iterate through each element of mat1, and if the element is not zero, perform the corresponding row-column multiplication and update the result in mat3. This avoids unnecessary multiplications by zero during the process.

## A solution in Javascript

```javascript
function multiply(mat1, mat2) {
    const m = mat1.length;
    const k = mat1[0].length;
    const n = mat2[0].length;
    const result = Array.from({ length: m }, () => Array.from({ length: n }, () => 0));
    for (let i = 0; i < m; i++) {
        for (let j = 0; j < k; j++) {
            if (mat1[i][j] !== 0) {
                for (let l = 0; l < n; l++) {
                    result[i][l] += mat1[i][j] * mat2[j][l];
                }
            }
        }
    }
    return result;
}
```
Iterate through each element of mat1, and if the element is not zero, perform the corresponding row-column multiplication and update the result in mat3. This avoids unnecessary multiplications by zero during the process.


# Burst Balloons

- slug: burst-balloons
- difficulty: Hard

You are given `n` balloons, indexed from `0` to `n - 1`. Each balloon is painted with a number on it represented by an array `nums`. You are asked to burst all the balloons.

If you burst the `ith` balloon, you will get `nums[i - 1] * nums[i] * nums[i + 1]` coins. If `i - 1` or `i + 1` goes out of bounds of the array, then treat it as if there is a balloon with a `1` painted on it.

Return _the maximum coins you can collect by bursting the balloons wisely_.

**Example 1:**

**Input:** nums = \[3,1,5,8\]
**Output:** 167
**Explanation:**
nums = \[3,1,5,8\] --> \[3,5,8\] --> \[3,8\] --> \[8\] --> \[\]
coins =  3\*1\*5    +   3\*5\*8   +  1\*3\*8  + 1\*8\*1 = 167

**Example 2:**

**Input:** nums = \[1,5\]
**Output:** 10

**Constraints:**

*   `n == nums.length`
*   `1 <= n <= 300`
*   `0 <= nums[i] <= 100`

## A solution in Java

```java
public int maxCoins(int[] nums) {
    int n = nums.length;
    int[] newNums = new int[n + 2];
    newNums[0] = 1;
    newNums[n + 1] = 1;
    for (int i = 1; i <= n; i++) {
        newNums[i] = nums[i - 1];
    }

    int[][] dp = new int[n + 2][n + 2];
    for (int len = 1; len <= n; len++) {
        for (int left = 1; left <= n - len + 1; left++) {
            int right = left + len - 1;
            for (int i = left; i <= right; i++) {
                dp[left][right] = Math.max(dp[left][right], newNums[left - 1] * newNums[i] * newNums[right + 1] + dp[left][i - 1] + dp[i + 1][right]);
            }
        }
    }

    return dp[1][n];
}
```
This problem can be solved using dynamic programming. We define a 2D array `dp` where `dp[left][right]` represents the maximum coins we can get by bursting the balloons from index `left` to `right`. To fill `dp`, we iterate over all possible subarrays (by varying length) and calculate the optimal solution for each subarray by choosing the bursting order. For each subarray, we iterate over all balloons, bursting the `i`th balloon and taking the maximum value between the current `dp[left][right]` and the obtained coins by bursting the `i`th balloon + the coins obtained by bursting the balloons on the left of `i`th balloon + the coins obtained by bursting the balloons on the right of `i`th balloon. Finally, we return `dp[1][n - 2]` since we added dummy balloons with value 1 at the beginning and end.

## A solution in C++

```cpp
int maxCoins(vector<int>& nums) {
    int n = nums.size();
    nums.insert(nums.begin(), 1);
    nums.push_back(1);

    vector<vector<int>> dp(n + 2, vector<int>(n + 2, 0));
    for (int len = 1; len <= n; len++) {
        for (int left = 1; left <= n - len + 1; left++) {
            int right = left + len - 1;
            for (int i = left; i <= right; i++) {
                dp[left][right] = max(dp[left][right], nums[left - 1] * nums[i] * nums[right + 1] + dp[left][i - 1] + dp[i + 1][right]);
            }
        }
    }

    return dp[1][n];
}
```
This problem can be solved using dynamic programming. We define a 2D array `dp` where `dp[left][right]` represents the maximum coins we can get by bursting the balloons from index `left` to `right`. To fill `dp`, we iterate over all possible subarrays (by varying length) and calculate the optimal solution for each subarray by choosing the bursting order. For each subarray, we iterate over all balloons, bursting the `i`th balloon and taking the maximum value between the current `dp[left][right]` and the obtained coins by bursting the `i`th balloon + the coins obtained by bursting the balloons on the left of `i`th balloon + the coins obtained by bursting the balloons on the right of `i`th balloon. Finally, we return `dp[1][n - 2]` since we added dummy balloons with value 1 at the beginning and end.

## A solution in Python

```python
def maxCoins(nums):
    nums = [1] + nums + [1]
    n = len(nums)
    dp = [[0] * n for _ in range(n)]

    for length in range(1, n - 1):
        for left in range(1, n - length):
            right = left + length - 1
            for i in range(left, right + 1):
                dp[left][right] = max(dp[left][right], nums[left - 1] * nums[i] * nums[right + 1] + dp[left][i - 1] + dp[i + 1][right])

    return dp[1][n - 2]
```
This problem can be solved using dynamic programming. We define a 2D array `dp` where `dp[left][right]` represents the maximum coins we can get by bursting the balloons from index `left` to `right`. To fill `dp`, we iterate over all possible subarrays (by varying length) and calculate the optimal solution for each subarray by choosing the bursting order. For each subarray, we iterate over all balloons, bursting the `i`th balloon and taking the maximum value between the current `dp[left][right]` and the obtained coins by bursting the `i`th balloon + the coins obtained by bursting the balloons on the left of `i`th balloon + the coins obtained by bursting the balloons on the right of `i`th balloon. Finally, we return `dp[1][n - 2]` since we added dummy balloons with value 1 at the beginning and end.

## A solution in Javascript

```javascript
function maxCoins(nums) {
    nums.unshift(1);
    nums.push(1);
    const n = nums.length;

    const dp = [];
    for (let i = 0; i < n; i++) {
        dp.push(new Array(n).fill(0));
    }

    for (let len = 1; len <= n - 2; len++) {
        for (let left = 1; left <= n - len - 1; left++) {
            const right = left + len - 1;
            for (let i = left; i <= right; i++) {
                dp[left][right] = Math.max(dp[left][right], nums[left - 1] * nums[i] * nums[right + 1] + dp[left][i - 1] + dp[i + 1][right]);
            }
        }
    }

    return dp[1][n - 2];
}
```
This problem can be solved using dynamic programming. We define a 2D array `dp` where `dp[left][right]` represents the maximum coins we can get by bursting the balloons from index `left` to `right`. To fill `dp`, we iterate over all possible subarrays (by varying length) and calculate the optimal solution for each subarray by choosing the bursting order. For each subarray, we iterate over all balloons, bursting the `i`th balloon and taking the maximum value between the current `dp[left][right]` and the obtained coins by bursting the `i`th balloon + the coins obtained by bursting the balloons on the left of `i`th balloon + the coins obtained by bursting the balloons on the right of `i`th balloon. Finally, we return `dp[1][n - 2]` since we added dummy balloons with value 1 at the beginning and end.


# Super Ugly Number

- slug: super-ugly-number
- difficulty: Medium

A **super ugly number** is a positive integer whose prime factors are in the array `primes`.

Given an integer `n` and an array of integers `primes`, return _the_ `nth` _**super ugly number**_.

The `nth` **super ugly number** is **guaranteed** to fit in a **32-bit** signed integer.

**Example 1:**

**Input:** n = 12, primes = \[2,7,13,19\]
**Output:** 32
**Explanation:** \[1,2,4,7,8,13,14,16,19,26,28,32\] is the sequence of the first 12 super ugly numbers given primes = \[2,7,13,19\].

**Example 2:**

**Input:** n = 1, primes = \[2,3,5\]
**Output:** 1
**Explanation:** 1 has no prime factors, therefore all of its prime factors are in the array primes = \[2,3,5\].

**Constraints:**

*   `1 <= n <= 105`
*   `1 <= primes.length <= 100`
*   `2 <= primes[i] <= 1000`
*   `primes[i]` is **guaranteed** to be a prime number.
*   All the values of `primes` are **unique** and sorted in **ascending order**.

## A solution in Java

```java
public int nthSuperUglyNumber(int n, int[] primes) {
    int[] ugly = new int[n];
    ugly[0] = 1;
    int[] indices = new int[primes.length];

    for (int i = 1; i < n; i++) {
        int minVal = Integer.MAX_VALUE;

        for (int j = 0; j < primes.length; j++)
            minVal = Math.min(minVal, ugly[indices[j]] * primes[j]);

        ugly[i] = minVal;

        for (int j = 0; j < primes.length; j++)
            if (ugly[i] == ugly[indices[j]] * primes[j])
                indices[j]++;
    }

    return ugly[n - 1];
}
```
The algorithm uses dynamic programming to find the nth super ugly number. We first create an `ugly` array of size `n`, where `ugly[i]` will store the (i+1)th super ugly number. We initialize `ugly[0]` as 1, since 1 is always a super ugly number.

Maintain an `indices` array of size `primes.length`, initialized with zeros. Each element `indices[j]` represents the index of the next super ugly number to multiply by `primes[j]`.

For each `i` from 1 to n, we calculate `ugly[i]` as the minimum of `ugly[indices[j]] * primes[j]` for all `j`. Then we increment the index `indices[j]` for which the condition `ugly[i] == ugly[indices[j]] * primes[j]` holds.

Finally, we return the last element of the `ugly` array, which is the nth super ugly number.

## A solution in C++

```cpp
int nthSuperUglyNumber(int n, vector<int>& primes) {
    vector<int> ugly(n);
    ugly[0] = 1;
    vector<int> indices(primes.size(), 0);

    for (int i = 1; i < n; i++) {
        int min_val = INT_MAX;

        for (int j = 0; j < primes.size(); j++)
            min_val = min(min_val, ugly[indices[j]] * primes[j]);

        ugly[i] = min_val;

        for (int j = 0; j < primes.size(); j++)
            if (ugly[i] == ugly[indices[j]] * primes[j])
                indices[j]++;
    }

    return ugly.back();
}
```
The algorithm uses dynamic programming to find the nth super ugly number. We first create an `ugly` array of size `n`, where `ugly[i]` will store the (i+1)th super ugly number. We initialize `ugly[0]` as 1, since 1 is always a super ugly number.

Maintain an `indices` array of size `primes.length`, initialized with zeros. Each element `indices[j]` represents the index of the next super ugly number to multiply by `primes[j]`.

For each `i` from 1 to n, we calculate `ugly[i]` as the minimum of `ugly[indices[j]] * primes[j]` for all `j`. Then we increment the index `indices[j]` for which the condition `ugly[i] == ugly[indices[j]] * primes[j]` holds.

Finally, we return the last element of the `ugly` array, which is the nth super ugly number.

## A solution in Python

```python
def nthSuperUglyNumber(n, primes):
    ugly = [0] * n
    ugly[0] = 1
    indices = [0] * len(primes)

    for i in range(1, n):
        min_val = float("inf")

        for j in range(len(primes)):
            min_val = min(min_val, ugly[indices[j]] * primes[j])

        ugly[i] = min_val

        for j in range(len(primes)):
            if ugly[i] == ugly[indices[j]] * primes[j]:
                indices[j] += 1

    return ugly[-1]
```
The algorithm uses dynamic programming to find the nth super ugly number. We first create an `ugly` array of size `n`, where `ugly[i]` will store the (i+1)th super ugly number. We initialize `ugly[0]` as 1, since 1 is always a super ugly number.

Maintain an `indices` array of size `primes.length`, initialized with zeros. Each element `indices[j]` represents the index of the next super ugly number to multiply by `primes[j]`.

For each `i` from 1 to n, we calculate `ugly[i]` as the minimum of `ugly[indices[j]] * primes[j]` for all `j`. Then we increment the index `indices[j]` for which the condition `ugly[i] == ugly[indices[j]] * primes[j]` holds.

Finally, we return the last element of the `ugly` array, which is the nth super ugly number.

## A solution in Javascript

```javascript
function nthSuperUglyNumber(n, primes) {
    let ugly = new Array(n);
    ugly[0] = 1;
    let indices = new Array(primes.length).fill(0);

    for (let i = 1; i < n; i++) {
        let minVal = Number.MAX_SAFE_INTEGER;

        for (let j = 0; j < primes.length; j++)
            minVal = Math.min(minVal, ugly[indices[j]] * primes[j]);

        ugly[i] = minVal;

        for (let j = 0; j < primes.length; j++)
            if (ugly[i] == ugly[indices[j]] * primes[j])
                indices[j]++;
    }

    return ugly[n - 1];
}
```
The algorithm uses dynamic programming to find the nth super ugly number. We first create an `ugly` array of size `n`, where `ugly[i]` will store the (i+1)th super ugly number. We initialize `ugly[0]` as 1, since 1 is always a super ugly number.

Maintain an `indices` array of size `primes.length`, initialized with zeros. Each element `indices[j]` represents the index of the next super ugly number to multiply by `primes[j]`.

For each `i` from 1 to n, we calculate `ugly[i]` as the minimum of `ugly[indices[j]] * primes[j]` for all `j`. Then we increment the index `indices[j]` for which the condition `ugly[i] == ugly[indices[j]] * primes[j]` holds.

Finally, we return the last element of the `ugly` array, which is the nth super ugly number.