# Single Element in a Sorted Array

- slug: single-element-in-a-sorted-array
- difficulty: Medium

You are given a sorted array consisting of only integers where every element appears exactly twice, except for one element which appears exactly once.

Return _the single element that appears only once_.

Your solution must run in `O(log n)` time and `O(1)` space.

**Example 1:**

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

**Example 2:**

**Input:** nums = \[3,3,7,7,10,11,11\]
**Output:** 10

**Constraints:**

*   `1 <= nums.length <= 105`
*   `0 <= nums[i] <= 105`

## A solution in Java

```java
public int singleNonDuplicate(int[] nums) {
    int low = 0, high = nums.length - 1;
    while (low < high) {
        int mid = low + (high - low) / 2;
        if (mid % 2 == 1)
            mid--;
        if (nums[mid] == nums[mid + 1])
            low = mid + 2;
        else
            high = mid;
    }
    return nums[low];
}
```
The algorithm starts by initializing two pointers, `low` and `high`, to the start and end indices of the given array. Then, it enters a loop that continues until `low` is greater or equal to `high`. In each iteration, the algorithm calculates the index in the middle of the range `[low, high]` and checks if the middle index is odd. If it is, it subtracts 1 from it to make it even.

The algorithm then checks if the middle element is equal to the element immediately after it. If it is, it means that the single element is on the right side of the middle index, so it updates the `low` pointer to be `mid + 2`. Otherwise, it updates the `high` pointer to be `mid`.

After the loop ends, the algorithm returns the element at the index stored in the `low` pointer, which is the single non-duplicate element.

## A solution in C++

```cpp
int singleNonDuplicate(vector<int>& nums) {
    int low = 0, high = nums.size() - 1;
    while (low < high) {
        int mid = low + (high - low) / 2;
        if (mid % 2 == 1)
            mid--;
        if (nums[mid] == nums[mid + 1])
            low = mid + 2;
        else
            high = mid;
    }
    return nums[low];
}
```
The algorithm starts by initializing two pointers, `low` and `high`, to the start and end indices of the given array. Then, it enters a loop that continues until `low` is greater or equal to `high`. In each iteration, the algorithm calculates the index in the middle of the range `[low, high]` and checks if the middle index is odd. If it is, it subtracts 1 from it to make it even.

The algorithm then checks if the middle element is equal to the element immediately after it. If it is, it means that the single element is on the right side of the middle index, so it updates the `low` pointer to be `mid + 2`. Otherwise, it updates the `high` pointer to be `mid`.

After the loop ends, the algorithm returns the element at the index stored in the `low` pointer, which is the single non-duplicate element.

## A solution in Python

```python
def singleNonDuplicate(nums):
    low, high = 0, len(nums) - 1
    while low < high:
        mid = low + (high - low) // 2
        if mid % 2 == 1:
            mid -= 1
        if nums[mid] == nums[mid + 1]:
            low = mid + 2
        else:
            high = mid
    return nums[low]
```
The algorithm starts by initializing two pointers, `low` and `high`, to the start and end indices of the given array. Then, it enters a loop that continues until `low` is greater or equal to `high`. In each iteration, the algorithm calculates the index in the middle of the range `[low, high]` and checks if the middle index is odd. If it is, it subtracts 1 from it to make it even.

The algorithm then checks if the middle element is equal to the element immediately after it. If it is, it means that the single element is on the right side of the middle index, so it updates the `low` pointer to be `mid + 2`. Otherwise, it updates the `high` pointer to be `mid`.

After the loop ends, the algorithm returns the element at the index stored in the `low` pointer, which is the single non-duplicate element.

## A solution in Javascript

```javascript
function singleNonDuplicate(nums) {
    let low = 0, high = nums.length - 1;
    while (low < high) {
        let mid = low + Math.floor((high - low) / 2);
        if (mid % 2 === 1)
            mid--;
        if (nums[mid] === nums[mid + 1])
            low = mid + 2;
        else
            high = mid;
    }
    return nums[low];
}
```
The algorithm starts by initializing two pointers, `low` and `high`, to the start and end indices of the given array. Then, it enters a loop that continues until `low` is greater or equal to `high`. In each iteration, the algorithm calculates the index in the middle of the range `[low, high]` and checks if the middle index is odd. If it is, it subtracts 1 from it to make it even.

The algorithm then checks if the middle element is equal to the element immediately after it. If it is, it means that the single element is on the right side of the middle index, so it updates the `low` pointer to be `mid + 2`. Otherwise, it updates the `high` pointer to be `mid`.

After the loop ends, the algorithm returns the element at the index stored in the `low` pointer, which is the single non-duplicate element.


# Reverse String II

- slug: reverse-string-ii
- difficulty: Easy

Given a string `s` and an integer `k`, reverse the first `k` characters for every `2k` characters counting from the start of the string.

If there are fewer than `k` characters left, reverse all of them. If there are less than `2k` but greater than or equal to `k` characters, then reverse the first `k` characters and leave the other as original.

**Example 1:**

**Input:** s = "abcdefg", k = 2
**Output:** "bacdfeg"

**Example 2:**

**Input:** s = "abcd", k = 2
**Output:** "bacd"

**Constraints:**

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

## A solution in Java

```java
public String reverseStr(String s, int k) {
    char[] chars = s.toCharArray();
    for (int i = 0; i < chars.length; i += 2 * k) {
        int left = i;
        int right = Math.min(i + k - 1, chars.length - 1);
        while (left < right) {
            char temp = chars[left];
            chars[left++] = chars[right];
            chars[right--] = temp;
        }
    }
    return new String(chars);
}
```
The algorithm first creates a mutable array from the original string. Then, we iterate over every 2k characters. If there are at least k characters remaining from the current position, we reverse the first k characters. Otherwise, we reverse all the remaining characters.

In C++, we use the `reverse` function that takes iterators as arguments. In Java, JavaScript, and Python, we use custom loops for reversing k characters, taking into account the case when there are fewer than k characters remaining. Then, we join the characters back into a string.

## A solution in C++

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

string reverseStr(string s, int k) {
    for (int i = 0; i < s.size(); i += 2*k) {
        if (i + k <= s.size()) {
            reverse(s.begin() + i, s.begin() + i + k);
        } else {
            reverse(s.begin() + i, s.end());
        }
    }
    return s;
}
```
The algorithm first creates a mutable array from the original string. Then, we iterate over every 2k characters. If there are at least k characters remaining from the current position, we reverse the first k characters. Otherwise, we reverse all the remaining characters.

In C++, we use the `reverse` function that takes iterators as arguments. In Java, JavaScript, and Python, we use custom loops for reversing k characters, taking into account the case when there are fewer than k characters remaining. Then, we join the characters back into a string.

## A solution in Python

```python
def reverseStr(s, k):
    chars = list(s)
    for i in range(0, len(chars), 2 * k):
        chars[i:i + k] = reversed(chars[i:i + k])
    return "".join(chars)
```
The algorithm first creates a mutable array from the original string. Then, we iterate over every 2k characters. If there are at least k characters remaining from the current position, we reverse the first k characters. Otherwise, we reverse all the remaining characters.

In C++, we use the `reverse` function that takes iterators as arguments. In Java, JavaScript, and Python, we use custom loops for reversing k characters, taking into account the case when there are fewer than k characters remaining. Then, we join the characters back into a string.

## A solution in Javascript

```javascript
function reverseStr(s, k) {
    let chars = s.split("");
    for (let i = 0; i < chars.length; i += 2 * k) {
        let left = i;
        let right = Math.min(i + k - 1, chars.length - 1);
        while (left < right) {
            [chars[left++], chars[right--]] = [chars[right], chars[left]];
        }
    }
    return chars.join("");
}
```
The algorithm first creates a mutable array from the original string. Then, we iterate over every 2k characters. If there are at least k characters remaining from the current position, we reverse the first k characters. Otherwise, we reverse all the remaining characters.

In C++, we use the `reverse` function that takes iterators as arguments. In Java, JavaScript, and Python, we use custom loops for reversing k characters, taking into account the case when there are fewer than k characters remaining. Then, we join the characters back into a string.


# 01 Matrix

- slug: 01-matrix
- difficulty: Medium

Given an `m x n` binary matrix `mat`, return _the distance of the nearest_ `0` _for each cell_.

The distance between two adjacent cells is `1`.

**Example 1:**

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

**Example 2:**

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

**Constraints:**

*   `m == mat.length`
*   `n == mat[i].length`
*   `1 <= m, n <= 104`
*   `1 <= m * n <= 104`
*   `mat[i][j]` is either `0` or `1`.
*   There is at least one `0` in `mat`.

## A solution in Java

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

public int[][] updateMatrix(int[][] mat) {
    int m = mat.length;
    int n = mat[0].length;
    int[][] distance = new int[m][n];
    Queue<int[]> queue = new LinkedList<>();

    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (mat[i][j] == 0) {
                distance[i][j] = 0;
                queue.add(new int[]{i, j});
            } else {
                distance[i][j] = Integer.MAX_VALUE;
            }
        }
    }

    int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    while (!queue.isEmpty()) {
        int[] current = queue.poll();
        int x = current[0];
        int y = current[1];

        for (int[] dir : directions) {
            int newX = x + dir[0];
            int newY = y + dir[1];
            if (newX >= 0 && newY >= 0 && newX < m && newY < n && distance[newX][newY] > distance[x][y] + 1) {
                distance[newX][newY] = distance[x][y] + 1;
                queue.add(new int[]{newX, newY});
            }
        }
    }
    return distance;
}
```
1. Initialize an m x n matrix `distance` with 0 values and a queue.
2. Iterate through the input matrix, setting the distance values to either 0 or infinity based on the original matrix value. For 0 values, push their coordinates to the queue.
3. Define the 4 possible directions to move in the matrix.
4. Use BFS (Breadth-First Search) to find the shortest distance to the nearest 0 for each cell:
   a. Pop a cell (x, y) from the queue.
   b. Iterate through each direction, checking if the new position is valid and the current distance is less than the current recorded position's distance.
   c. If the new distance is shorter, update the distance and push the new position's coordinates to the queue.
5. Return the `distance` matrix.

## A solution in C++

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

vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
    int m = mat.size();
    int n = mat[0].size();
    vector<vector<int>> ans(m, vector<int>(n, INT_MAX - 100000));

    queue<pair<int, int>> q;
    for (int i = 0; i < m; i++) {
        for (int j = 0; j < n; j++) {
            if (mat[i][j] == 0) {
                ans[i][j] = 0;
                q.push({i, j});
            }
        }
    }

    vector<pair<int, int>> dirs = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
    while (!q.empty()) {
        int x = q.front().first;
        int y = q.front().second;
        q.pop();

        for (pair<int, int>& dir : dirs) {
            int newX = x + dir.first;
            int newY = y + dir.second;
            if (newX >= 0 && newY >= 0 && newX < m && newY < n && ans[newX][newY] > ans[x][y] + 1) {
                ans[newX][newY] = ans[x][y] + 1;
                q.push({newX, newY});
            }
        }
    }
    return ans;
}
```
1. Initialize an m x n matrix `distance` with 0 values and a queue.
2. Iterate through the input matrix, setting the distance values to either 0 or infinity based on the original matrix value. For 0 values, push their coordinates to the queue.
3. Define the 4 possible directions to move in the matrix.
4. Use BFS (Breadth-First Search) to find the shortest distance to the nearest 0 for each cell:
   a. Pop a cell (x, y) from the queue.
   b. Iterate through each direction, checking if the new position is valid and the current distance is less than the current recorded position's distance.
   c. If the new distance is shorter, update the distance and push the new position's coordinates to the queue.
5. Return the `distance` matrix.

## A solution in Python

```python
from collections import deque

def updateMatrix(mat):
    m, n = len(mat), len(mat[0])
    distance = [[0 if mat[i][j] == 0 else float('inf') for j in range(n)] for i in range(m)]
    queue = deque([(i, j) for i in range(m) for j in range(n) if mat[i][j] == 0])

    directions = [(1, 0), (-1, 0), (0, 1), (0, -1)]
    while queue:
        x, y = queue.popleft()
        for dx, dy in directions:
            newX, newY = x + dx, y + dy
            if 0 <= newX < m and 0 <= newY < n and distance[newX][newY] > distance[x][y] + 1:
                distance[newX][newY] = distance[x][y] + 1
                queue.append((newX, newY))

    return distance
```
1. Initialize an m x n matrix `distance` with 0 values and a queue.
2. Iterate through the input matrix, setting the distance values to either 0 or infinity based on the original matrix value. For 0 values, push their coordinates to the queue.
3. Define the 4 possible directions to move in the matrix.
4. Use BFS (Breadth-First Search) to find the shortest distance to the nearest 0 for each cell:
   a. Pop a cell (x, y) from the queue.
   b. Iterate through each direction, checking if the new position is valid and the current distance is less than the current recorded position's distance.
   c. If the new distance is shorter, update the distance and push the new position's coordinates to the queue.
5. Return the `distance` matrix.

## A solution in Javascript

```javascript
function updateMatrix(mat) {
    let m = mat.length;
    let n = mat[0].length;
    let distance = Array.from({ length: m }, () => Array.from({ length: n }, () => Infinity));
    let queue = [];

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

    let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]];
    while (queue.length) {
        let [x, y] = queue.shift();
        for (const [dx, dy] of directions) {
            let newX = x + dx;
            let newY = y + dy;
            if (newX >= 0 && newY >= 0 && newX < m && newY < n && distance[newX][newY] > distance[x][y] + 1) {
                distance[newX][newY] = distance[x][y] + 1;
                queue.push([newX, newY]);
            }
        }
    }
    return distance;
}
```
1. Initialize an m x n matrix `distance` with 0 values and a queue.
2. Iterate through the input matrix, setting the distance values to either 0 or infinity based on the original matrix value. For 0 values, push their coordinates to the queue.
3. Define the 4 possible directions to move in the matrix.
4. Use BFS (Breadth-First Search) to find the shortest distance to the nearest 0 for each cell:
   a. Pop a cell (x, y) from the queue.
   b. Iterate through each direction, checking if the new position is valid and the current distance is less than the current recorded position's distance.
   c. If the new distance is shorter, update the distance and push the new position's coordinates to the queue.
5. Return the `distance` matrix.


# Diameter of Binary Tree

- slug: diameter-of-binary-tree
- difficulty: Easy

Given the `root` of a binary tree, return _the length of the **diameter** of the tree_.

The **diameter** of a binary tree is the **length** of the longest path between any two nodes in a tree. This path may or may not pass through the `root`.

The **length** of a path between two nodes is represented by the number of edges between them.

**Example 1:**

**Input:** root = \[1,2,3,4,5\]
**Output:** 3
**Explanation:** 3 is the length of the path \[4,2,1,3\] or \[5,2,1,3\].

**Example 2:**

**Input:** root = \[1,2\]
**Output:** 1

**Constraints:**

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

## A solution in Java

```java
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public int[] diameterHelper(TreeNode root) {
    if (root == null) return new int[]{0, 0};
    int[] left = diameterHelper(root.left);
    int[] right = diameterHelper(root.right);
    int maxHeight = 1 + Math.max(left[0], right[0]);
    int maxDiameter = Math.max(left[0] + right[0], Math.max(left[1], right[1]));
    return new int[]{maxHeight, maxDiameter};
}

public int diameterOfBinaryTree(TreeNode root) {
    return diameterHelper(root)[1];
}
```
1. Create a helper function to return a tuple/array with two values:
   - The height of the subtree rooted at the given node
   - The largest diameter among the subtree's nodes
2. If the node is null/None, return (0, 0), as the height and diameter are both 0.
3. Recurse on the left and right children, obtaining their heights and diameters.
4. The height at the current node is 1 + the maximum of the left and right heights.
5. The diameter at the current node is the maximum of the following three values:
   - The sum of the left and right heights (the path goes through the root)
   - The left child's diameter
   - The right child's diameter
6. Return the diameter of the tree as the second element in the output tuple/array of the helper function called with the root node.

## A solution in C++

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

int diameterOfBinaryTree(TreeNode* root, int* height) {
    int leftHeight = 0, rightHeight = 0;
    if (root == nullptr) {
        *height = 0;
        return 0;
    }
    int leftDiameter = diameterOfBinaryTree(root->left, &leftHeight);
    int rightDiameter = diameterOfBinaryTree(root->right, &rightHeight);
    *height = std::max(leftHeight, rightHeight) + 1;
    return std::max(std::max(leftDiameter, rightDiameter), leftHeight + rightHeight);
}
```
1. Create a helper function to return a tuple/array with two values:
   - The height of the subtree rooted at the given node
   - The largest diameter among the subtree's nodes
2. If the node is null/None, return (0, 0), as the height and diameter are both 0.
3. Recurse on the left and right children, obtaining their heights and diameters.
4. The height at the current node is 1 + the maximum of the left and right heights.
5. The diameter at the current node is the maximum of the following three values:
   - The sum of the left and right heights (the path goes through the root)
   - The left child's diameter
   - The right child's diameter
6. Return the diameter of the tree as the second element in the output tuple/array of the helper function called with the root node.

## A solution in Python

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

def diameter_of_binary_tree(root):
    def _diameter_of_binary_tree(node):
        if not node:
            return 0, 0
        left_height, left_diameter = _diameter_of_binary_tree(node.left)
        right_height, right_diameter = _diameter_of_binary_tree(node.right)
        height = 1 + max(left_height, right_height)
        diameter = max(left_height + right_height, max(left_diameter, right_diameter))
        return height, diameter

    return _diameter_of_binary_tree(root)[1]
```
1. Create a helper function to return a tuple/array with two values:
   - The height of the subtree rooted at the given node
   - The largest diameter among the subtree's nodes
2. If the node is null/None, return (0, 0), as the height and diameter are both 0.
3. Recurse on the left and right children, obtaining their heights and diameters.
4. The height at the current node is 1 + the maximum of the left and right heights.
5. The diameter at the current node is the maximum of the following three values:
   - The sum of the left and right heights (the path goes through the root)
   - The left child's diameter
   - The right child's diameter
6. Return the diameter of the tree as the second element in the output tuple/array of the helper function called with the root node.

## A solution in Javascript

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

function diameterOfBinaryTree(root) {
    function diameterHelper(node) {
        if (!node) return [0, 0];
        let [leftHeight, leftDiameter] = diameterHelper(node.left);
        let [rightHeight, rightDiameter] = diameterHelper(node.right);
        let maxHeight = 1 + Math.max(leftHeight, rightHeight);
        let maxDiameter = Math.max(leftHeight + rightHeight, Math.max(leftDiameter, rightDiameter));
        return [maxHeight, maxDiameter];
    }

    return diameterHelper(root)[1];
}
```
1. Create a helper function to return a tuple/array with two values:
   - The height of the subtree rooted at the given node
   - The largest diameter among the subtree's nodes
2. If the node is null/None, return (0, 0), as the height and diameter are both 0.
3. Recurse on the left and right children, obtaining their heights and diameters.
4. The height at the current node is 1 + the maximum of the left and right heights.
5. The diameter at the current node is the maximum of the following three values:
   - The sum of the left and right heights (the path goes through the root)
   - The left child's diameter
   - The right child's diameter
6. Return the diameter of the tree as the second element in the output tuple/array of the helper function called with the root node.


# Output Contest Matches

- slug: output-contest-matches
- difficulty: Medium

During the NBA playoffs, we always set the rather strong team to play with the rather weak team, like make the rank `1` team play with the rank `nth` team, which is a good strategy to make the contest more interesting.

Given `n` teams, return _their final contest matches in the form of a string_.

The `n` teams are labeled from `1` to `n`, which represents their initial rank (i.e., Rank `1` is the strongest team and Rank `n` is the weakest team).

We will use parentheses `'('`, and `')'` and commas `','` to represent the contest team pairing. We use the parentheses for pairing and the commas for partition. During the pairing process in each round, you always need to follow the strategy of making the rather strong one pair with the rather weak one.

**Example 1:**

**Input:** n = 4
**Output:**  "((1,4),(2,3)) "
**Explanation:**
In the first round, we pair the team 1 and 4, the teams 2 and 3 together, as we need to make the strong team and weak team together.
And we got (1, 4),(2, 3).
In the second round, the winners of (1, 4) and (2, 3) need to play again to generate the final winner, so you need to add the paratheses outside them.
And we got the final answer ((1,4),(2,3)).

**Example 2:**

**Input:** n = 8
**Output:**  "(((1,8),(4,5)),((2,7),(3,6))) "
**Explanation:**
First round: (1, 8),(2, 7),(3, 6),(4, 5)
Second round: ((1, 8),(4, 5)),((2, 7),(3, 6))
Third round: (((1, 8),(4, 5)),((2, 7),(3, 6)))
Since the third round will generate the final winner, you need to output the answer (((1,8),(4,5)),((2,7),(3,6))).

**Constraints:**

*   `n == 2x` where `x` in in the range `[1, 12]`.

## A solution in Java

```java
public String findContestMatch(int n) {
    String[] matches = new String[n];
    for (int i = 1; i <= n; i++) {
        matches[i - 1] = Integer.toString(i);
    }

    while (n > 1) {
        for (int i = 0; i < n / 2; i++) {
            matches[i] = "(" + matches[i] + "," + matches[n - 1 - i] + ")";
        }
        n /= 2;
    }

    return matches[0];
}
```
This algorithm initializes an array of matches with `n` elements, each representing a team. It then generates one half of the final contest matches using a while loop. During each iteration of the while loop, for every pair of teams `i` and `n - 1 - i`, we form a new match by creating a string with the format `(team1,team2)` and store it in the matches array. With each iteration, we divide the number of matches by 2, which eventually gives us the final contest match at the first index of the matches array.

## A solution in C++

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

string findContestMatch(int n) {
    vector<string> matches(n);
    for (int i = 1; i <= n; i++) {
        matches[i - 1] = to_string(i);
    }

    while (n > 1) {
        for (int i = 0; i < n / 2; i++) {
            matches[i] = "(" + matches[i] + "," + matches[n - 1 - i] + ")";
        }
        n /= 2;
    }

    return matches[0];
}
```
This algorithm initializes an array of matches with `n` elements, each representing a team. It then generates one half of the final contest matches using a while loop. During each iteration of the while loop, for every pair of teams `i` and `n - 1 - i`, we form a new match by creating a string with the format `(team1,team2)` and store it in the matches array. With each iteration, we divide the number of matches by 2, which eventually gives us the final contest match at the first index of the matches array.

## A solution in Python

```python
def findContestMatch(n):
    matches = [str(i) for i in range(1, n + 1)]

    while n > 1:
        for i in range(n // 2):
            matches[i] = "(" + matches[i] + "," + matches[n - 1 - i] + ")"
        n //= 2

    return matches[0]
```
This algorithm initializes an array of matches with `n` elements, each representing a team. It then generates one half of the final contest matches using a while loop. During each iteration of the while loop, for every pair of teams `i` and `n - 1 - i`, we form a new match by creating a string with the format `(team1,team2)` and store it in the matches array. With each iteration, we divide the number of matches by 2, which eventually gives us the final contest match at the first index of the matches array.

## A solution in Javascript

```javascript
function findContestMatch(n) {
    let matches = Array.from({length: n}, (_, i) => String(i + 1));

    while (n > 1) {
        for (let i = 0; i < (n / 2); i++) {
            matches[i] = "(" + matches[i] + "," + matches[n - 1 - i] + ")";
        }
        n = Math.floor(n / 2);
    }

    return matches[0];
}
```
This algorithm initializes an array of matches with `n` elements, each representing a team. It then generates one half of the final contest matches using a while loop. During each iteration of the while loop, for every pair of teams `i` and `n - 1 - i`, we form a new match by creating a string with the format `(team1,team2)` and store it in the matches array. With each iteration, we divide the number of matches by 2, which eventually gives us the final contest match at the first index of the matches array.


# Boundary of Binary Tree

- slug: boundary-of-binary-tree
- difficulty: Medium

The **boundary** of a binary tree is the concatenation of the **root**, the **left boundary**, the **leaves** ordered from left-to-right, and the **reverse order** of the **right boundary**.

The **left boundary** is the set of nodes defined by the following:

*   The root node's left child is in the left boundary. If the root does not have a left child, then the left boundary is **empty**.
*   If a node in the left boundary and has a left child, then the left child is in the left boundary.
*   If a node is in the left boundary, has **no** left child, but has a right child, then the right child is in the left boundary.
*   The leftmost leaf is **not** in the left boundary.

The **right boundary** is similar to the **left boundary**, except it is the right side of the root's right subtree. Again, the leaf is **not** part of the **right boundary**, and the **right boundary** is empty if the root does not have a right child.

The **leaves** are nodes that do not have any children. For this problem, the root is **not** a leaf.

Given the `root` of a binary tree, return _the values of its **boundary**_.

**Example 1:**

**Input:** root = \[1,null,2,3,4\]
**Output:** \[1,3,4,2\]
**Explanation:**
- The left boundary is empty because the root does not have a left child.
- The right boundary follows the path starting from the root's right child 2 -> 4.
  4 is a leaf, so the right boundary is \[2\].
- The leaves from left to right are \[3,4\].
Concatenating everything results in \[1\] + \[\] + \[3,4\] + \[2\] = \[1,3,4,2\].

**Example 2:**

**Input:** root = \[1,2,3,4,5,6,null,null,null,7,8,9,10\]
**Output:** \[1,2,4,7,8,9,10,6,3\]
**Explanation:**
- The left boundary follows the path starting from the root's left child 2 -> 4.
  4 is a leaf, so the left boundary is \[2\].
- The right boundary follows the path starting from the root's right child 3 -> 6 -> 10.
  10 is a leaf, so the right boundary is \[3,6\], and in reverse order is \[6,3\].
- The leaves from left to right are \[4,7,8,9,10\].
Concatenating everything results in \[1\] + \[2\] + \[4,7,8,9,10\] + \[6,3\] = \[1,2,4,7,8,9,10,6,3\].

**Constraints:**

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

## A solution in Java

```java
class Solution {
    public void leftBoundary(TreeNode node, List<Integer> boundary) {
        if (node == null || (node.left == null && node.right == null)) return;
        boundary.add(node.val);
        if (node.left != null) leftBoundary(node.left, boundary);
        else leftBoundary(node.right, boundary);
    }

    public void rightBoundary(TreeNode node, List<Integer> boundary) {
        if (node == null || (node.left == null && node.right == null)) return;
        if (node.right != null) rightBoundary(node.right, boundary);
        else rightBoundary(node.left, boundary);
        boundary.add(node.val);
    }

    public void leaves(TreeNode node, List<Integer> boundary) {
        if (node == null) return;
        if (node.left == null && node.right == null) {
            boundary.add(node.val);
        }
        leaves(node.left, boundary);
        leaves(node.right, boundary);
    }

    public List<Integer> boundaryOfBinaryTree(TreeNode root) {
        List<Integer> res = new ArrayList<>();
        if (root == null) return res;
        res.add(root.val);
        leftBoundary(root.left, res);
        leaves(root, res);
        rightBoundary(root.right, res);
        return res;
    }
}
```
The algorithm consists of two main parts: traversing the tree and appending the values to the boundary list. At a high level, the steps are as follows:

1. If the tree is empty, return an empty list.
2. Add the root value to the boundary list.
3. Traverse the left boundary, appending nodes' values as visited. This is done recursively, prioritizing the left child over the right child.
4. Traverse the tree and append the values of any leaves encountered.
5. Traverse the right boundary, appending nodes' values as visited. This is done backwards to account for the reverse order requirement of the right boundary.

The leftBoundary and rightBoundary functions are mostly the same, except the rightBoundary function adds values in reverse. The leaves function traverses the entire tree, adding values of any leaves encountered.

## A solution in C++

```cpp
class Solution {
public:
    void leftBoundary(TreeNode* node, vector<int>& boundary) {
        if (!node || (!node->left && !node->right)) return;
        boundary.push_back(node->val);
        if (node->left) leftBoundary(node->left, boundary);
        else leftBoundary(node->right, boundary);
    }

    void rightBoundary(TreeNode* node, vector<int>& boundary) {
        if (!node || (!node->left && !node->right)) return;
        if (node->right) rightBoundary(node->right, boundary);
        else rightBoundary(node->left, boundary);
        boundary.push_back(node->val);
    }

    void leaves(TreeNode* node, vector<int>& boundary) {
        if (!node) return;
        if (!node->left && !node->right) {
            boundary.push_back(node->val);
        }
        leaves(node->left, boundary);
        leaves(node->right, boundary);
    }

    vector<int> boundaryOfBinaryTree(TreeNode* root) {
        vector<int> res;
        if (!root) return res;
        res.push_back(root->val);
        leftBoundary(root->left, res);
        leaves(root, res);
        rightBoundary(root->right, res);
        return res;
    }
};
```
The algorithm consists of two main parts: traversing the tree and appending the values to the boundary list. At a high level, the steps are as follows:

1. If the tree is empty, return an empty list.
2. Add the root value to the boundary list.
3. Traverse the left boundary, appending nodes' values as visited. This is done recursively, prioritizing the left child over the right child.
4. Traverse the tree and append the values of any leaves encountered.
5. Traverse the right boundary, appending nodes' values as visited. This is done backwards to account for the reverse order requirement of the right boundary.

The leftBoundary and rightBoundary functions are mostly the same, except the rightBoundary function adds values in reverse. The leaves function traverses the entire tree, adding values of any leaves encountered.

## A solution in Python

```python
class Solution:
    def leftBoundary(self, node, boundary):
        if not node or not (node.left or node.right):
            return
        boundary.append(node.val)
        if node.left:
            self.leftBoundary(node.left, boundary)
        else:
            self.leftBoundary(node.right, boundary)

    def rightBoundary(self, node, boundary):
        if not node or not (node.left or node.right):
            return
        if node.right:
            self.rightBoundary(node.right, boundary)
        else:
            self.rightBoundary(node.left, boundary)
        boundary.append(node.val)

    def leaves(self, node, boundary):
        if not node:
            return
        if not (node.left or node.right):
            boundary.append(node.val)
        self.leaves(node.left, boundary)
        self.leaves(node.right, boundary)

    def boundaryOfBinaryTree(self, root):
        res = []
        if not root:
            return res
        res.append(root.val)
        self.leftBoundary(root.left, res)
        self.leaves(root, res)
        self.rightBoundary(root.right, res)
        return res
```
The algorithm consists of two main parts: traversing the tree and appending the values to the boundary list. At a high level, the steps are as follows:

1. If the tree is empty, return an empty list.
2. Add the root value to the boundary list.
3. Traverse the left boundary, appending nodes' values as visited. This is done recursively, prioritizing the left child over the right child.
4. Traverse the tree and append the values of any leaves encountered.
5. Traverse the right boundary, appending nodes' values as visited. This is done backwards to account for the reverse order requirement of the right boundary.

The leftBoundary and rightBoundary functions are mostly the same, except the rightBoundary function adds values in reverse. The leaves function traverses the entire tree, adding values of any leaves encountered.

## A solution in Javascript

```javascript
class Solution {
    leftBoundary(node, boundary) {
        if (!node || (!node.left && !node.right)) return;
        boundary.push(node.val);
        if (node.left) this.leftBoundary(node.left, boundary);
        else this.leftBoundary(node.right, boundary);
    }

    rightBoundary(node, boundary) {
        if (!node || (!node.left && !node.right)) return;
        if (node.right) this.rightBoundary(node.right, boundary);
        else this.rightBoundary(node.left, boundary);
        boundary.push(node.val);
    }

    leaves(node, boundary) {
        if (!node) return;
        if (!node.left && !node.right) {
            boundary.push(node.val);
        }
        this.leaves(node.left, boundary);
        this.leaves(node.right, boundary);
    }

    boundaryOfBinaryTree(root) {
        let res = [];
        if (!root) return res;

        res.push(root.val);
        this.leftBoundary(root.left, res);
        this.leaves(root, res);
        this.rightBoundary(root.right, res);
        return res;
    }
}
```
The algorithm consists of two main parts: traversing the tree and appending the values to the boundary list. At a high level, the steps are as follows:

1. If the tree is empty, return an empty list.
2. Add the root value to the boundary list.
3. Traverse the left boundary, appending nodes' values as visited. This is done recursively, prioritizing the left child over the right child.
4. Traverse the tree and append the values of any leaves encountered.
5. Traverse the right boundary, appending nodes' values as visited. This is done backwards to account for the reverse order requirement of the right boundary.

The leftBoundary and rightBoundary functions are mostly the same, except the rightBoundary function adds values in reverse. The leaves function traverses the entire tree, adding values of any leaves encountered.


# Remove Boxes

- slug: remove-boxes
- difficulty: Hard

You are given several `boxes` with different colors represented by different positive numbers.

You may experience several rounds to remove boxes until there is no box left. Each time you can choose some continuous boxes with the same color (i.e., composed of `k` boxes, `k >= 1`), remove them and get `k * k` points.

Return _the maximum points you can get_.

**Example 1:**

**Input:** boxes = \[1,3,2,2,2,3,4,3,1\]
**Output:** 23
**Explanation:**
\[1, 3, 2, 2, 2, 3, 4, 3, 1\]
----> \[1, 3, 3, 4, 3, 1\] (3\*3=9 points)
----> \[1, 3, 3, 3, 1\] (1\*1=1 points)
----> \[1, 1\] (3\*3=9 points)
----> \[\] (2\*2=4 points)

**Example 2:**

**Input:** boxes = \[1,1,1\]
**Output:** 9

**Example 3:**

**Input:** boxes = \[1\]
**Output:** 1

**Constraints:**

*   `1 <= boxes.length <= 100`
*   `1 <= boxes[i] <= 100`

## A solution in Java

```java
public int removeBoxes(int[] boxes) {
    int[][][] dp = new int[100][100][100];
    return dfs(boxes, dp, 0, boxes.length - 1, 0);
}

private int dfs(int[] boxes, int[][][] dp, int l, int r, int k) {
    if (l > r) return 0;
    if (dp[l][r][k] != 0) return dp[l][r][k];

    while (r > l && boxes[r] == boxes[r - 1]) {r--; k++;}

    dp[l][r][k] = (k + 1) * (k + 1) + dfs(boxes, dp, l, r - 1, 0);

    for (int i = l; i < r; i++) {
        if (boxes[i] == boxes[r]) {
            dp[l][r][k] = Math.max(dp[l][r][k], dfs(boxes, dp, l, i, k + 1) + dfs(boxes, dp, i + 1, r - 1, 0));
        }
    }

    return dp[l][r][k];
}
```
The problem can be solved using dynamic programming. We can define a 3D DP table where `dp[l][r][k]` will be the maximum points we can get for the boxes in the range `[l, r]`, where there are `k` boxes with the same color as `boxes[r]` to the right of `boxes[r]`.

We'll use a DFS approach to fill our DP table.
1. First, we check whether our current range `l > r`, in which case we return 0.
2. If `dp[l][r][k]` already has a non-zero value, we return `dp[l][r][k]`.
3. Then, we remove all continuous boxes with the same color as `boxes[r]` on the right side of `boxes[r]` to calculate the initial value of `dp[l][r][k]`.
4. We iterate from `l` to `r` and whenever we find a box with the same color as `boxes[r]`, we update `dp[l][r][k]` with the maximum of the current value and the sum of the result we get in the current split and the result that we have found for the next continuous split.

Finally, we return the value in `dp[0][boxes.length - 1][0]`, which gives us the maximum points that can be obtained for the given input.

## A solution in C++

```cpp
int removeBoxes(vector<int>& boxes) {
    int dp[100][100][100] = {0};
    return dfs(boxes, dp, 0, boxes.size() - 1, 0);
}

int dfs(vector<int>& boxes, int dp[100][100][100], int l, int r, int k) {
    if (l > r) return 0;
    if (dp[l][r][k] != 0) return dp[l][r][k];

    while (r > l && boxes[r] == boxes[r - 1]) {r--; k++;}

    dp[l][r][k] = (k + 1) * (k + 1) + dfs(boxes, dp, l, r - 1, 0);

    for (int i = l; i < r; i++) {
        if (boxes[i] == boxes[r]) {
            dp[l][r][k] = max(dp[l][r][k], dfs(boxes, dp, l, i, k + 1) + dfs(boxes, dp, i + 1, r - 1, 0));
        }
    }

    return dp[l][r][k];
}
```
The problem can be solved using dynamic programming. We can define a 3D DP table where `dp[l][r][k]` will be the maximum points we can get for the boxes in the range `[l, r]`, where there are `k` boxes with the same color as `boxes[r]` to the right of `boxes[r]`.

We'll use a DFS approach to fill our DP table.
1. First, we check whether our current range `l > r`, in which case we return 0.
2. If `dp[l][r][k]` already has a non-zero value, we return `dp[l][r][k]`.
3. Then, we remove all continuous boxes with the same color as `boxes[r]` on the right side of `boxes[r]` to calculate the initial value of `dp[l][r][k]`.
4. We iterate from `l` to `r` and whenever we find a box with the same color as `boxes[r]`, we update `dp[l][r][k]` with the maximum of the current value and the sum of the result we get in the current split and the result that we have found for the next continuous split.

Finally, we return the value in `dp[0][boxes.length - 1][0]`, which gives us the maximum points that can be obtained for the given input.

## A solution in Python

```python
def removeBoxes(boxes):
    def dfs(l, r, k):
        if l > r: return 0
        if dp[l][r][k] != 0: return dp[l][r][k]

        while r > l and boxes[r] == boxes[r - 1]:
            r -= 1
            k += 1

        dp[l][r][k] = (k + 1) * (k + 1) + dfs(l, r - 1, 0)

        for i in range(l, r):
            if boxes[i] == boxes[r]:
                dp[l][r][k] = max(dp[l][r][k], dfs(l, i, k + 1) + dfs(i + 1, r - 1, 0))

        return dp[l][r][k]

    dp = [[[0] * 100 for _ in xrange(100)] for _ in xrange(100)]
    return dfs(0, len(boxes) - 1, 0)
```
The problem can be solved using dynamic programming. We can define a 3D DP table where `dp[l][r][k]` will be the maximum points we can get for the boxes in the range `[l, r]`, where there are `k` boxes with the same color as `boxes[r]` to the right of `boxes[r]`.

We'll use a DFS approach to fill our DP table.
1. First, we check whether our current range `l > r`, in which case we return 0.
2. If `dp[l][r][k]` already has a non-zero value, we return `dp[l][r][k]`.
3. Then, we remove all continuous boxes with the same color as `boxes[r]` on the right side of `boxes[r]` to calculate the initial value of `dp[l][r][k]`.
4. We iterate from `l` to `r` and whenever we find a box with the same color as `boxes[r]`, we update `dp[l][r][k]` with the maximum of the current value and the sum of the result we get in the current split and the result that we have found for the next continuous split.

Finally, we return the value in `dp[0][boxes.length - 1][0]`, which gives us the maximum points that can be obtained for the given input.

## A solution in Javascript

```javascript
function removeBoxes(boxes) {
    const dfs = (l, r, k) => {
        if (l > r) return 0;
        if (dp[l][r][k] !== 0) return dp[l][r][k];

        while (r > l && boxes[r] == boxes[r - 1]) {r--; k++;}

        dp[l][r][k] = (k + 1) * (k + 1) + dfs(l, r - 1, 0);

        for (let i = l; i < r; i++) {
            if (boxes[i] == boxes[r]) {
                dp[l][r][k] = Math.max(dp[l][r][k], dfs(l, i, k + 1) + dfs(i + 1, r - 1, 0));
            }
        }

        return dp[l][r][k];
    };

    let dp = Array.from({ length: 100 }, () => Array.from({ length: 100 }, () => Array(100).fill(0)));
    return dfs(0, boxes.length - 1, 0);
}
```
The problem can be solved using dynamic programming. We can define a 3D DP table where `dp[l][r][k]` will be the maximum points we can get for the boxes in the range `[l, r]`, where there are `k` boxes with the same color as `boxes[r]` to the right of `boxes[r]`.

We'll use a DFS approach to fill our DP table.
1. First, we check whether our current range `l > r`, in which case we return 0.
2. If `dp[l][r][k]` already has a non-zero value, we return `dp[l][r][k]`.
3. Then, we remove all continuous boxes with the same color as `boxes[r]` on the right side of `boxes[r]` to calculate the initial value of `dp[l][r][k]`.
4. We iterate from `l` to `r` and whenever we find a box with the same color as `boxes[r]`, we update `dp[l][r][k]` with the maximum of the current value and the sum of the result we get in the current split and the result that we have found for the next continuous split.

Finally, we return the value in `dp[0][boxes.length - 1][0]`, which gives us the maximum points that can be obtained for the given input.


# Number of Provinces

- slug: number-of-provinces
- difficulty: Medium

There are `n` cities. Some of them are connected, while some are not. If city `a` is connected directly with city `b`, and city `b` is connected directly with city `c`, then city `a` is connected indirectly with city `c`.

A **province** is a group of directly or indirectly connected cities and no other cities outside of the group.

You are given an `n x n` matrix `isConnected` where `isConnected[i][j] = 1` if the `ith` city and the `jth` city are directly connected, and `isConnected[i][j] = 0` otherwise.

Return _the total number of **provinces**_.

**Example 1:**

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

**Example 2:**

**Input:** isConnected = \[\[1,0,0\],\[0,1,0\],\[0,0,1\]\]
**Output:** 3

**Constraints:**

*   `1 <= n <= 200`
*   `n == isConnected.length`
*   `n == isConnected[i].length`
*   `isConnected[i][j]` is `1` or `0`.
*   `isConnected[i][i] == 1`
*   `isConnected[i][j] == isConnected[j][i]`

## A solution in Java

```java
public int findCircleNum(int[][] isConnected) {
    int provinces = 0;
    boolean[] visited = new boolean[isConnected.length];
    for (int i = 0; i < isConnected.length; i++) {
        if (!visited[i]) {
            dfs(isConnected, visited, i);
            provinces++;
        }
    }
    return provinces;
}

private void dfs(int[][] isConnected, boolean[] visited, int i) {
    visited[i] = true;
    for (int j = 0; j < isConnected.length; j++) {
        if (isConnected[i][j] == 1 && !visited[j]) {
            dfs(isConnected, visited, j);
        }
    }
}
```
We can solve this problem by using Depth First Search (DFS) to traverse the graph of cities:

1. Create a boolean array `visited` of size n (the number of cities) initialized with `false` values.
2. Initialize a counter variable `provinces` to count the number of provinces and set it to 0.
3. Iterate through each city from 0 to n-1.
   - If the city has not been visited, call a DFS helper function to traverse the connected components.
   - Increment the `provinces` counter for every new group of connected cities.
4. In the DFS helper function, mark the given city `i` as visited.
5. Iterate through all other cities from 0 to n-1.
   - If the cities `i` and `j` are directly connected (isConnected[i][j] == 1) and city `j` has not been visited, call the DFS helper function with city `j`.
6. Return the total number of provinces.

This algorithm ensures that all directly and indirectly connected cities are visited, and their connected components are counted as provinces. The time complexity of this algorithm is O(n^2) as in the worst case, we might have to visit all possible edge connections between cities.

## A solution in C++

```cpp
#include <vector>

using std::vector;

void dfs(vector<vector<int>>& isConnected, vector<bool>& visited, int i) {
    visited[i] = true;
    for (int j = 0; j < isConnected.size(); j++) {
        if (isConnected[i][j] == 1 && !visited[j]) {
            dfs(isConnected, visited, j);
        }
    }
}

int findCircleNum(vector<vector<int>>& isConnected) {
    int provinces = 0;
    vector<bool> visited(isConnected.size(), false);
    for (int i = 0; i < isConnected.size(); i++) {
        if (!visited[i]) {
            dfs(isConnected, visited, i);
            provinces++;
        }
    }
    return provinces;
}
```
We can solve this problem by using Depth First Search (DFS) to traverse the graph of cities:

1. Create a boolean array `visited` of size n (the number of cities) initialized with `false` values.
2. Initialize a counter variable `provinces` to count the number of provinces and set it to 0.
3. Iterate through each city from 0 to n-1.
   - If the city has not been visited, call a DFS helper function to traverse the connected components.
   - Increment the `provinces` counter for every new group of connected cities.
4. In the DFS helper function, mark the given city `i` as visited.
5. Iterate through all other cities from 0 to n-1.
   - If the cities `i` and `j` are directly connected (isConnected[i][j] == 1) and city `j` has not been visited, call the DFS helper function with city `j`.
6. Return the total number of provinces.

This algorithm ensures that all directly and indirectly connected cities are visited, and their connected components are counted as provinces. The time complexity of this algorithm is O(n^2) as in the worst case, we might have to visit all possible edge connections between cities.

## A solution in Python

```python
def findCircleNum(isConnected):
    def dfs(isConnected, visited, i):
        visited[i] = True
        for j in range(len(isConnected)):
            if isConnected[i][j] == 1 and not visited[j]:
                dfs(isConnected, visited, j)

    provinces = 0
    visited = [False] * len(isConnected)
    for i in range(len(isConnected)):
        if not visited[i]:
            dfs(isConnected, visited, i)
            provinces += 1
    return provinces
```
We can solve this problem by using Depth First Search (DFS) to traverse the graph of cities:

1. Create a boolean array `visited` of size n (the number of cities) initialized with `false` values.
2. Initialize a counter variable `provinces` to count the number of provinces and set it to 0.
3. Iterate through each city from 0 to n-1.
   - If the city has not been visited, call a DFS helper function to traverse the connected components.
   - Increment the `provinces` counter for every new group of connected cities.
4. In the DFS helper function, mark the given city `i` as visited.
5. Iterate through all other cities from 0 to n-1.
   - If the cities `i` and `j` are directly connected (isConnected[i][j] == 1) and city `j` has not been visited, call the DFS helper function with city `j`.
6. Return the total number of provinces.

This algorithm ensures that all directly and indirectly connected cities are visited, and their connected components are counted as provinces. The time complexity of this algorithm is O(n^2) as in the worst case, we might have to visit all possible edge connections between cities.

## A solution in Javascript

```javascript
function findCircleNum(isConnected) {
    function dfs(isConnected, visited, i) {
        visited[i] = true;
        for (let j = 0; j < isConnected.length; j++) {
            if (isConnected[i][j] === 1 && !visited[j]) {
                dfs(isConnected, visited, j);
            }
        }
    }

    let provinces = 0;
    const visited = new Array(isConnected.length).fill(false);
    for (let i = 0; i < isConnected.length; i++) {
        if (!visited[i]) {
            dfs(isConnected, visited, i);
            provinces++;
        }
    }
    return provinces;
}
```
We can solve this problem by using Depth First Search (DFS) to traverse the graph of cities:

1. Create a boolean array `visited` of size n (the number of cities) initialized with `false` values.
2. Initialize a counter variable `provinces` to count the number of provinces and set it to 0.
3. Iterate through each city from 0 to n-1.
   - If the city has not been visited, call a DFS helper function to traverse the connected components.
   - Increment the `provinces` counter for every new group of connected cities.
4. In the DFS helper function, mark the given city `i` as visited.
5. Iterate through all other cities from 0 to n-1.
   - If the cities `i` and `j` are directly connected (isConnected[i][j] == 1) and city `j` has not been visited, call the DFS helper function with city `j`.
6. Return the total number of provinces.

This algorithm ensures that all directly and indirectly connected cities are visited, and their connected components are counted as provinces. The time complexity of this algorithm is O(n^2) as in the worst case, we might have to visit all possible edge connections between cities.


# Split Array with Equal Sum

- slug: split-array-with-equal-sum
- difficulty: Hard

Given an integer array `nums` of length `n`, return `true` if there is a triplet `(i, j, k)` which satisfies the following conditions:

*   `0 < i, i + 1 < j, j + 1 < k < n - 1`
*   The sum of subarrays `(0, i - 1)`, `(i + 1, j - 1)`, `(j + 1, k - 1)` and `(k + 1, n - 1)` is equal.

A subarray `(l, r)` represents a slice of the original array starting from the element indexed `l` to the element indexed `r`.

**Example 1:**

**Input:** nums = \[1,2,1,2,1,2,1\]
**Output:** true
**Explanation:**
i = 1, j = 3, k = 5.
sum(0, i - 1) = sum(0, 0) = 1
sum(i + 1, j - 1) = sum(2, 2) = 1
sum(j + 1, k - 1) = sum(4, 4) = 1
sum(k + 1, n - 1) = sum(6, 6) = 1

**Example 2:**

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

**Constraints:**

*   `n == nums.length`
*   `1 <= n <= 2000`
*   `-106 <= nums[i] <= 106`

## A solution in Java

```java
boolean find_triplet_equal_sum(int[] nums) {
    int n = nums.length;
    int[] prefix_sum = new int[n + 1];

    for (int i = 0; i < n; ++i) {
        prefix_sum[i + 1] = prefix_sum[i] + nums[i];
    }

    for (int i = 1; i + 2 < n; ++i) {
        for (int j = i + 2; j + 1 < n; ++j) {
            for (int k = j + 2; k < n; ++k) {
                int s1 = prefix_sum[i];
                int s2 = prefix_sum[j] - prefix_sum[i + 1];
                int s3 = prefix_sum[k] - prefix_sum[j + 1];
                int s4 = prefix_sum[n] - prefix_sum[k + 1];
                if (s1 == s2 && s2 == s3 && s3 == s4) {
                    return true;
                }
            }
        }
    }
    return false;
}
```
The problem can be solved by calculating the prefix sum of the given `nums` array to optimize the sum calculation of subarrays. We use three nested loops to iterate through all possible values of `i`, `j`, and `k`. To check if the sum of the subarrays specified in the problem statement are equal, compare `s1`, `s2`, `s3` and `s4` which represent the sum of these subarrays, and return `true` if they are equal. If no triplet is found after iterating through all possible combinations, return `false`.

## A solution in C++

```cpp
bool find_triplet_equal_sum(const std::vector<int>& nums) {
    int n = nums.size();
    std::vector<int> prefix_sum(n + 1, 0);

    for (int i = 0; i < n; ++i) {
        prefix_sum[i + 1] = prefix_sum[i] + nums[i];
    }

    for (int i = 1; i + 2 < n; ++i) {
        for (int j = i + 2; j + 1 < n; ++j) {
            for (int k = j + 2; k < n; ++k) {
                int s1 = prefix_sum[i];
                int s2 = prefix_sum[j] - prefix_sum[i + 1];
                int s3 = prefix_sum[k] - prefix_sum[j + 1];
                int s4 = prefix_sum[n] - prefix_sum[k + 1];
                if (s1 == s2 && s2 == s3 && s3 == s4) {
                    return true;
                }
            }
        }
    }
    return false;
}
```
The problem can be solved by calculating the prefix sum of the given `nums` array to optimize the sum calculation of subarrays. We use three nested loops to iterate through all possible values of `i`, `j`, and `k`. To check if the sum of the subarrays specified in the problem statement are equal, compare `s1`, `s2`, `s3` and `s4` which represent the sum of these subarrays, and return `true` if they are equal. If no triplet is found after iterating through all possible combinations, return `false`.

## A solution in Python

```python
def find_triplet_equal_sum(nums):
    n = len(nums)
    prefix_sum = [0] * (n + 1)

    for i in range(n):
        prefix_sum[i + 1] = prefix_sum[i] + nums[i]

    for i in range(1, n - 2):
        for j in range(i + 2, n - 1):
            for k in range(j + 2, n):
                s1 = prefix_sum[i]
                s2 = prefix_sum[j] - prefix_sum[i + 1]
                s3 = prefix_sum[k] - prefix_sum[j + 1]
                s4 = prefix_sum[n] - prefix_sum[k + 1]
                if s1 == s2 == s3 == s4:
                    return True
    return False
```
The problem can be solved by calculating the prefix sum of the given `nums` array to optimize the sum calculation of subarrays. We use three nested loops to iterate through all possible values of `i`, `j`, and `k`. To check if the sum of the subarrays specified in the problem statement are equal, compare `s1`, `s2`, `s3` and `s4` which represent the sum of these subarrays, and return `true` if they are equal. If no triplet is found after iterating through all possible combinations, return `false`.

## A solution in Javascript

```javascript
function find_triplet_equal_sum(nums) {
    const n = nums.length;
    const prefix_sum = new Array(n + 1).fill(0);

    for (let i = 0; i < n; ++i) {
        prefix_sum[i + 1] = prefix_sum[i] + nums[i];
    }

    for (let i = 1; i + 2 < n; ++i) {
        for (let j = i + 2; j + 1 < n; ++j) {
            for (let k = j + 2; k < n; ++k) {
                const s1 = prefix_sum[i];
                const s2 = prefix_sum[j] - prefix_sum[i + 1];
                const s3 = prefix_sum[k] - prefix_sum[j + 1];
                const s4 = prefix_sum[n] - prefix_sum[k + 1];
                if (s1 === s2 && s2 === s3 && s3 === s4) {
                    return true;
                }
            }
        }
    }
    return false;
}
```
The problem can be solved by calculating the prefix sum of the given `nums` array to optimize the sum calculation of subarrays. We use three nested loops to iterate through all possible values of `i`, `j`, and `k`. To check if the sum of the subarrays specified in the problem statement are equal, compare `s1`, `s2`, `s3` and `s4` which represent the sum of these subarrays, and return `true` if they are equal. If no triplet is found after iterating through all possible combinations, return `false`.


# Binary Tree Longest Consecutive Sequence II

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

Given the `root` of a binary tree, return _the length of the longest consecutive path in the tree_.

A consecutive path is a path where the values of the consecutive nodes in the path differ by one. This path can be either increasing or decreasing.

*   For example, `[1,2,3,4]` and `[4,3,2,1]` are both considered valid, but the path `[1,2,4,3]` is not valid.

On the other hand, the path can be in the child-Parent-child order, where not necessarily be parent-child order.

**Example 1:**

**Input:** root = \[1,2,3\]
**Output:** 2
**Explanation:** The longest consecutive path is \[1, 2\] or \[2, 1\].

**Example 2:**

**Input:** root = \[2,1,3\]
**Output:** 3
**Explanation:** The longest consecutive path is \[1, 2, 3\] or \[3, 2, 1\].

**Constraints:**

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

## A solution in Java

```java
public class TreeNode {
    int val;
    TreeNode left;
    TreeNode right;
    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public int longestConsecutivePathUtil(TreeNode root, int[] maxLength) {
    if (root == null) return 0;
    int left = longestConsecutivePathUtil(root.left, maxLength) + 1;
    int right = longestConsecutivePathUtil(root.right, maxLength) + 1;
    if (root.left != null && root.left.val != root.val + 1) left = 1;
    if (root.right != null && root.right.val != root.val + 1) right = 1;
    int length = Math.max(left, right);
    maxLength[0] = Math.max(maxLength[0], left + right - 1);
    return length;
}

public int longestConsecutive(TreeNode root) {
    int[] maxLength = new int[1];
    longestConsecutivePathUtil(root, maxLength);
    return maxLength[0];
}
```
The algorithm starts traversing the tree in a depth first search (DFS) from the root till each of the leafs. For each consecutive increasing path, it increments the length by one. If a node value breaks the consecutive sequence, it resets the length of that subtree. It keeps track of the maximum length of the consecutive path found so far in any of the subtrees, and updates it when it finds a longer path. Finally, it returns that value.

## A solution in C++

```cpp
#include<algorithm>

class TreeNode {
public:
    int val;
    TreeNode *left;
    TreeNode *right;
    TreeNode() : val(0), left(nullptr), right(nullptr) {}
    TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
    TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
};

int longestConsecutivePathUtil(TreeNode* root, int& maxLength) {
    if (root == nullptr) return 0;
    int left = longestConsecutivePathUtil(root->left, maxLength) + 1;
    int right = longestConsecutivePathUtil(root->right, maxLength) + 1;
    if (root->left != nullptr && root->left->val != root->val + 1) left = 1;
    if (root->right != nullptr && root->right->val != root->val + 1) right = 1;
    int length = std::max(left, right);
    maxLength = std::max(maxLength, left + right - 1);
    return length;
}

int longestConsecutive(TreeNode* root) {
    int maxLength = 0;
    longestConsecutivePathUtil(root, maxLength);
    return maxLength;
}
```
The algorithm starts traversing the tree in a depth first search (DFS) from the root till each of the leafs. For each consecutive increasing path, it increments the length by one. If a node value breaks the consecutive sequence, it resets the length of that subtree. It keeps track of the maximum length of the consecutive path found so far in any of the subtrees, and updates it when it finds a longer path. Finally, it returns that value.

## A solution in Python

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

def longest_consecutive(root: TreeNode) -> int:
    def longest_consecutive_path_util(node, max_length):
        if not node:
            return 0
        left = longest_consecutive_path_util(node.left, max_length) + 1
        right = longest_consecutive_path_util(node.right, max_length) + 1
        if node.left and node.left.val != node.val + 1:
            left = 1
        if node.right and node.right.val != node.val + 1:
            right = 1
        length = max(left, right)
        max_length[0] = max(max_length[0], left + right - 1)
        return length

    max_length = [0]
    longest_consecutive_path_util(root, max_length)
    return max_length[0]
```
The algorithm starts traversing the tree in a depth first search (DFS) from the root till each of the leafs. For each consecutive increasing path, it increments the length by one. If a node value breaks the consecutive sequence, it resets the length of that subtree. It keeps track of the maximum length of the consecutive path found so far in any of the subtrees, and updates it when it finds a longer path. Finally, it returns that value.

## A solution in Javascript

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

function longestConsecutivePath(root) {
    function longestConsecutivePathUtil(node, maxLength) {
        if (!node) {
            return 0;
        }
        let left = longestConsecutivePathUtil(node.left, maxLength) + 1;
        let right = longestConsecutivePathUtil(node.right, maxLength) + 1;
        if (node.left && node.left.val !== node.val + 1) {
            left = 1;
        }
        if (node.right && node.right.val !== node.val + 1) {
            right = 1;
        }
        let length = Math.max(left, right);
        maxLength[0] = Math.max(maxLength[0], left + right - 1);
        return length;
    }

    let maxLength = [0];
    longestConsecutivePathUtil(root, maxLength);
    return maxLength[0];
}
```
The algorithm starts traversing the tree in a depth first search (DFS) from the root till each of the leafs. For each consecutive increasing path, it increments the length by one. If a node value breaks the consecutive sequence, it resets the length of that subtree. It keeps track of the maximum length of the consecutive path found so far in any of the subtrees, and updates it when it finds a longer path. Finally, it returns that value.


# Student Attendance Record I

- slug: student-attendance-record-i
- difficulty: Easy

You are given a string `s` representing an attendance record for a student where each character signifies whether the student was absent, late, or present on that day. The record only contains the following three characters:

*   `'A'`: Absent.
*   `'L'`: Late.
*   `'P'`: Present.

The student is eligible for an attendance award if they meet **both** of the following criteria:

*   The student was absent (`'A'`) for **strictly** fewer than 2 days **total**.
*   The student was **never** late (`'L'`) for 3 or more **consecutive** days.

Return `true` _if the student is eligible for an attendance award, or_ `false` _otherwise_.

**Example 1:**

**Input:** s =  "PPALLP "
**Output:** true
**Explanation:** The student has fewer than 2 absences and was never late 3 or more consecutive days.

**Example 2:**

**Input:** s =  "PPALLL "
**Output:** false
**Explanation:** The student was late 3 consecutive days in the last 3 days, so is not eligible for the award.

**Constraints:**

*   `1 <= s.length <= 1000`
*   `s[i]` is either `'A'`, `'L'`, or `'P'`.

## A solution in Java

```java
public boolean checkRecord(String s) {
    int late = 0, absent = 0;
    for (int i = 0; i < s.length(); i++) {
        if (s.charAt(i) == 'A') {
            absent++;
            late = 0;
        } else if (s.charAt(i) == 'L') {
            late++;
        } else {
            late = 0;
        }

        if (absent >= 2 || late >= 3) return false;
    }
    return true;
}
```
The algorithm initializes variables `late` and `absent` as counters for late and absent days, respectively.
1. Iterate through each character of the string `s`.
2. If the current character is 'A', increment the `absent` counter and set `late` counter to zero.
3. If the current character is 'L', increment the `late` counter.
4. If the current character is 'P', set the `late` counter to zero.
5. After processing each character, check if `absent` is greater or equal to 2, or if `late` is greater or equal to 3. If either condition is met, return false (ineligible for an attendance award).
6. If the entire string has been processed without meeting the conditions, return true (eligible for an attendance award).

## A solution in C++

```cpp
#include <string>

bool checkRecord(std::string s) {
    int late = 0, absent = 0;
    for (int i = 0; i < s.length(); i++) {
        if (s[i] == 'A') {
            absent++;
            late = 0;
        } else if (s[i] == 'L') {
            late++;
        } else {
            late = 0;
        }

        if (absent >= 2 || late >= 3) return false;
    }
    return true;
}
```
The algorithm initializes variables `late` and `absent` as counters for late and absent days, respectively.
1. Iterate through each character of the string `s`.
2. If the current character is 'A', increment the `absent` counter and set `late` counter to zero.
3. If the current character is 'L', increment the `late` counter.
4. If the current character is 'P', set the `late` counter to zero.
5. After processing each character, check if `absent` is greater or equal to 2, or if `late` is greater or equal to 3. If either condition is met, return false (ineligible for an attendance award).
6. If the entire string has been processed without meeting the conditions, return true (eligible for an attendance award).

## A solution in Python

```python
def checkRecord(s: str) -> bool:
    late, absent = 0, 0
    for c in s:
        if c == 'A':
            absent += 1
            late = 0
        elif c == 'L':
            late += 1
        else:
            late = 0

        if absent >= 2 or late >= 3:
            return False
    return True
```
The algorithm initializes variables `late` and `absent` as counters for late and absent days, respectively.
1. Iterate through each character of the string `s`.
2. If the current character is 'A', increment the `absent` counter and set `late` counter to zero.
3. If the current character is 'L', increment the `late` counter.
4. If the current character is 'P', set the `late` counter to zero.
5. After processing each character, check if `absent` is greater or equal to 2, or if `late` is greater or equal to 3. If either condition is met, return false (ineligible for an attendance award).
6. If the entire string has been processed without meeting the conditions, return true (eligible for an attendance award).

## A solution in Javascript

```javascript
function checkRecord(s) {
    let late = 0, absent = 0;
    for (let i = 0; i < s.length; i++) {
        if (s[i] === 'A') {
            absent++;
            late = 0;
        } else if (s[i] === 'L') {
            late++;
        } else {
            late = 0;
        }

        if (absent >= 2 || late >= 3) return false;
    }
    return true;
}
```
The algorithm initializes variables `late` and `absent` as counters for late and absent days, respectively.
1. Iterate through each character of the string `s`.
2. If the current character is 'A', increment the `absent` counter and set `late` counter to zero.
3. If the current character is 'L', increment the `late` counter.
4. If the current character is 'P', set the `late` counter to zero.
5. After processing each character, check if `absent` is greater or equal to 2, or if `late` is greater or equal to 3. If either condition is met, return false (ineligible for an attendance award).
6. If the entire string has been processed without meeting the conditions, return true (eligible for an attendance award).


# Student Attendance Record II

- slug: student-attendance-record-ii
- difficulty: Hard

An attendance record for a student can be represented as a string where each character signifies whether the student was absent, late, or present on that day. The record only contains the following three characters:

*   `'A'`: Absent.
*   `'L'`: Late.
*   `'P'`: Present.

Any student is eligible for an attendance award if they meet **both** of the following criteria:

*   The student was absent (`'A'`) for **strictly** fewer than 2 days **total**.
*   The student was **never** late (`'L'`) for 3 or more **consecutive** days.

Given an integer `n`, return _the **number** of possible attendance records of length_ `n` _that make a student eligible for an attendance award. The answer may be very large, so return it **modulo**_ `109 + 7`.

**Example 1:**

**Input:** n = 2
**Output:** 8
**Explanation:** There are 8 records with length 2 that are eligible for an award:
 "PP ",  "AP ",  "PA ",  "LP ",  "PL ",  "AL ",  "LA ",  "LL "
Only  "AA " is not eligible because there are 2 absences (there need to be fewer than 2).

**Example 2:**

**Input:** n = 1
**Output:** 3

**Example 3:**

**Input:** n = 10101
**Output:** 183236316

**Constraints:**

*   `1 <= n <= 105`

## A solution in Java

```java
public int checkRecord(int n) {
    int M = 1000000007;
    long[] dp = new long[6];  // {latent state 0, latent state 1, ..., latent state 5}
    Arrays.fill(dp, 1);
    while (n-- > 0) {
        long[] next_dp = new long[6];
        next_dp[0] = (dp[0] + dp[1] + dp[2]) % M;
        next_dp[1] = dp[0];
        next_dp[2] = dp[1];
        next_dp[3] = (dp[3] + dp[4] + dp[5]) % M;
        next_dp[4] = dp[3];
        next_dp[5] = dp[4];
        dp = next_dp;
    }
    return (int) ((dp[0] + dp[1] + dp[2] +
                   dp[3] + dp[4] + dp[5]) % M);
}
```
The algorithm uses dynamic programming to count the number of eligible attendance records. We use a latent state representation consisting of 6 states to account for previous attendance occurrences:

- latent state 0: no A or L
- latent state 1: no A, 1 consecutive L
- latent state 2: no A, 2 consecutive L
- latent state 3: 1 A, no L
- latent state 4: 1 A, 1 consecutive L
- latent state 5: 1 A, 2 consecutive L

In each iteration, we update these latent states according to the previous states. After n iterations, the sum of all latent states represents the number of eligible attendance records.

## A solution in C++

```cpp
int checkRecord(int n) {
    int M = 1000000007;
    vector<long long> dp(6, 1);  // {latent state 0, latent state 1, ..., latent state 5}
    while (n--) {
        vector<long long> next_dp(6, 0);
        next_dp[0] = (dp[0] + dp[1] + dp[2]) % M;
        next_dp[1] = dp[0];
        next_dp[2] = dp[1];
        next_dp[3] = (dp[3] + dp[4] + dp[5]) % M;
        next_dp[4] = dp[3];
        next_dp[5] = dp[4];
        dp = next_dp;
    }
    return (dp[0] + dp[1] + dp[2] + dp[3] + dp[4] + dp[5]) % M;
}
```
The algorithm uses dynamic programming to count the number of eligible attendance records. We use a latent state representation consisting of 6 states to account for previous attendance occurrences:

- latent state 0: no A or L
- latent state 1: no A, 1 consecutive L
- latent state 2: no A, 2 consecutive L
- latent state 3: 1 A, no L
- latent state 4: 1 A, 1 consecutive L
- latent state 5: 1 A, 2 consecutive L

In each iteration, we update these latent states according to the previous states. After n iterations, the sum of all latent states represents the number of eligible attendance records.

## A solution in Python

```python
def checkRecord(n: int) -> int:
    M = 1000000007
    dp = [1] * 6  # [latent state 0, latent state 1, ..., latent state 5]
    while n:
        next_dp = [0] * 6
        next_dp[0] = (dp[0] + dp[1] + dp[2]) % M
        next_dp[1] = dp[0]
        next_dp[2] = dp[1]
        next_dp[3] = (dp[3] + dp[4] + dp[5]) % M
        next_dp[4] = dp[3]
        next_dp[5] = dp[4]
        dp = next_dp
        n -= 1
    return sum(dp) % M
```
The algorithm uses dynamic programming to count the number of eligible attendance records. We use a latent state representation consisting of 6 states to account for previous attendance occurrences:

- latent state 0: no A or L
- latent state 1: no A, 1 consecutive L
- latent state 2: no A, 2 consecutive L
- latent state 3: 1 A, no L
- latent state 4: 1 A, 1 consecutive L
- latent state 5: 1 A, 2 consecutive L

In each iteration, we update these latent states according to the previous states. After n iterations, the sum of all latent states represents the number of eligible attendance records.

## A solution in Javascript

```javascript
function checkRecord(n) {
    let M = 1000000007;
    let dp = Array(6).fill(1);  // [latent state 0, latent state 1, ..., latent state 5]
    while (n--) {
        let next_dp = Array(6).fill(0);
        next_dp[0] = (dp[0] + dp[1] + dp[2]) % M;
        next_dp[1] = dp[0];
        next_dp[2] = dp[1];
        next_dp[3] = (dp[3] + dp[4] + dp[5]) % M;
        next_dp[4] = dp[3];
        next_dp[5] = dp[4];
        dp = next_dp;
    }
    return dp.reduce((sum, val) => (sum + val) % M, 0);
}
```
The algorithm uses dynamic programming to count the number of eligible attendance records. We use a latent state representation consisting of 6 states to account for previous attendance occurrences:

- latent state 0: no A or L
- latent state 1: no A, 1 consecutive L
- latent state 2: no A, 2 consecutive L
- latent state 3: 1 A, no L
- latent state 4: 1 A, 1 consecutive L
- latent state 5: 1 A, 2 consecutive L

In each iteration, we update these latent states according to the previous states. After n iterations, the sum of all latent states represents the number of eligible attendance records.


# Optimal Division

- slug: optimal-division
- difficulty: Medium

You are given an integer array `nums`. The adjacent integers in `nums` will perform the float division.

*   For example, for `nums = [2,3,4]`, we will evaluate the expression `"2/3/4 "`.

However, you can add any number of parenthesis at any position to change the priority of operations. You want to add these parentheses such the value of the expression after the evaluation is maximum.

Return _the corresponding expression that has the maximum value in string format_.

**Note:** your expression should not contain redundant parenthesis.

**Example 1:**

**Input:** nums = \[1000,100,10,2\]
**Output:**  "1000/(100/10/2) "
**Explanation:** 1000/(100/10/2) = 1000/((100/10)/2) = 200
However, the bold parenthesis in  "1000/(**(**100/10**)**/2) " are redundant since they do not influence the operation priority.
So you should return  "1000/(100/10/2) ".
Other cases:
1000/(100/10)/2 = 50
1000/(100/(10/2)) = 50
1000/100/10/2 = 0.5
1000/100/(10/2) = 2

**Example 2:**

**Input:** nums = \[2,3,4\]
**Output:**  "2/(3/4) "
**Explanation:** (2/(3/4)) = 8/3 = 2.667
It can be shown that after trying all possibilities, we cannot get an expression with evaluation greater than 2.667

**Constraints:**

*   `1 <= nums.length <= 10`
*   `2 <= nums[i] <= 1000`
*   There is only one optimal division for the given input.

## A solution in Java

```java
public String optimalDivision(int[] nums) {
    int n = nums.length;
    if (n == 1) return Integer.toString(nums[0]);
    if (n == 2) return Integer.toString(nums[0]) + "/" + Integer.toString(nums[1]);
    StringBuilder res = new StringBuilder(Integer.toString(nums[0]) + "/(");
    for (int i = 1; i < n - 1; ++i) {
        res.append(Integer.toString(nums[i])).append("/");
    }
    res.append(Integer.toString(nums[n - 1])).append(")");
    return res.toString();
}
```
The key to maximizing the result of the division expression is to minimize the divisors by grouping them together in parentheses. Since we want the entire array of numbers divided by the smallest possible divisor, we essentially want to maximize the division by ensuring the numbers in the array are divided by each other in sequence, from left to right.

The algorithm goes as follows:
1. If there's only one number, return that number.
2. If there are two numbers, a and b, just return "a/b" as the division expression.
3. For three or more numbers, create a string with the first number followed by "/(".
4. Iterate through the rest of the numbers, adding each number to the string followed by a "/". Stop at the second-to-last number in the array.
5. Add the very last number to the string followed by a closing parenthesis.
6. Return the constructed string.

This way, we get the maximum value for the division operation.

## A solution in C++

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

std::string optimalDivision(std::vector<int>& nums) {
    int n = nums.size();
    if (n == 1) return std::to_string(nums[0]);
    if (n == 2) return std::to_string(nums[0]) + "/" + std::to_string(nums[1]);
    std::string res = std::to_string(nums[0]) + "/(";
    for (int i = 1; i < n - 1; ++i) {
        res += std::to_string(nums[i]) + "/";
    }
    res += std::to_string(nums[n - 1]) + ")";
    return res;
}
```
The key to maximizing the result of the division expression is to minimize the divisors by grouping them together in parentheses. Since we want the entire array of numbers divided by the smallest possible divisor, we essentially want to maximize the division by ensuring the numbers in the array are divided by each other in sequence, from left to right.

The algorithm goes as follows:
1. If there's only one number, return that number.
2. If there are two numbers, a and b, just return "a/b" as the division expression.
3. For three or more numbers, create a string with the first number followed by "/(".
4. Iterate through the rest of the numbers, adding each number to the string followed by a "/". Stop at the second-to-last number in the array.
5. Add the very last number to the string followed by a closing parenthesis.
6. Return the constructed string.

This way, we get the maximum value for the division operation.

## A solution in Python

```python
def optimal_division(nums):
    n = len(nums)
    if n == 1:
        return str(nums[0])
    if n == 2:
        return str(nums[0]) + '/' + str(nums[1])
    res = str(nums[0]) + '/('
    for i in range(1, n - 1):
        res += str(nums[i]) + '/'
    res += str(nums[n - 1]) + ')'
    return res
```
The key to maximizing the result of the division expression is to minimize the divisors by grouping them together in parentheses. Since we want the entire array of numbers divided by the smallest possible divisor, we essentially want to maximize the division by ensuring the numbers in the array are divided by each other in sequence, from left to right.

The algorithm goes as follows:
1. If there's only one number, return that number.
2. If there are two numbers, a and b, just return "a/b" as the division expression.
3. For three or more numbers, create a string with the first number followed by "/(".
4. Iterate through the rest of the numbers, adding each number to the string followed by a "/". Stop at the second-to-last number in the array.
5. Add the very last number to the string followed by a closing parenthesis.
6. Return the constructed string.

This way, we get the maximum value for the division operation.

## A solution in Javascript

```javascript
function optimalDivision(nums) {
    const n = nums.length;
    if (n === 1) return nums[0].toString();
    if (n === 2) return nums[0].toString() + '/' + nums[1].toString();
    let res = nums[0].toString() + '/(';
    for (let i = 1; i < n - 1; ++i) {
        res += nums[i].toString() + '/';
    }
    res += nums[n - 1].toString() + ')';
    return res;
}
```
The key to maximizing the result of the division expression is to minimize the divisors by grouping them together in parentheses. Since we want the entire array of numbers divided by the smallest possible divisor, we essentially want to maximize the division by ensuring the numbers in the array are divided by each other in sequence, from left to right.

The algorithm goes as follows:
1. If there's only one number, return that number.
2. If there are two numbers, a and b, just return "a/b" as the division expression.
3. For three or more numbers, create a string with the first number followed by "/(".
4. Iterate through the rest of the numbers, adding each number to the string followed by a "/". Stop at the second-to-last number in the array.
5. Add the very last number to the string followed by a closing parenthesis.
6. Return the constructed string.

This way, we get the maximum value for the division operation.


# Brick Wall

- slug: brick-wall
- difficulty: Medium

There is a rectangular brick wall in front of you with `n` rows of bricks. The `ith` row has some number of bricks each of the same height (i.e., one unit) but they can be of different widths. The total width of each row is the same.

Draw a vertical line from the top to the bottom and cross the least bricks. If your line goes through the edge of a brick, then the brick is not considered as crossed. You cannot draw a line just along one of the two vertical edges of the wall, in which case the line will obviously cross no bricks.

Given the 2D array `wall` that contains the information about the wall, return _the minimum number of crossed bricks after drawing such a vertical line_.

**Example 1:**

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

**Example 2:**

**Input:** wall = \[\[1\],\[1\],\[1\]\]
**Output:** 3

**Constraints:**

*   `n == wall.length`
*   `1 <= n <= 104`
*   `1 <= wall[i].length <= 104`
*   `1 <= sum(wall[i].length) <= 2 * 104`
*   `sum(wall[i])` is the same for each row `i`.
*   `1 <= wall[i][j] <= 231 - 1`

## A solution in Java

```java
import java.util.List;
import java.util.HashMap;

public int leastBricks(List<List<Integer>> wall) {
    HashMap<Integer, Integer> edgeCount = new HashMap<>();
    int maxCount = 0;

    for (List<Integer> row : wall) {
        int edgePosition = 0;
        for (int i = 0; i < row.size() - 1; ++i) {
            edgePosition += row.get(i);
            edgeCount.put(edgePosition, edgeCount.getOrDefault(edgePosition, 0) + 1);
            maxCount = Math.max(maxCount, edgeCount.get(edgePosition));
        }
    }

    return wall.size() - maxCount;
}
```
1. Create a hashmap `edge_count` to store the number of edges encountered at each position and initialize `max_count` to 0.
2. Loop through each row in the wall.
3. For each row, loop through its bricks (excluding the last brick) and keep track of the current brick edge position.
4. Increment the count for the current edge position in the hashmap, then update `max_count` accordingly.
5. After looping through all the rows, the result is the total number of rows minus the `max_count`. This gives the minimum number of crossed bricks.

## A solution in C++

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

int leastBricks(std::vector<std::vector<int>>& wall) {
    std::unordered_map<int, int> edge_count;
    int max_count = 0;

    for (const auto& row : wall) {
        int edge_position = 0;
        for (size_t i = 0; i < row.size() - 1; ++i) {
            edge_position += row[i];
            ++edge_count[edge_position];
            max_count = std::max(max_count, edge_count[edge_position]);
        }
    }

    return wall.size() - max_count;
}
```
1. Create a hashmap `edge_count` to store the number of edges encountered at each position and initialize `max_count` to 0.
2. Loop through each row in the wall.
3. For each row, loop through its bricks (excluding the last brick) and keep track of the current brick edge position.
4. Increment the count for the current edge position in the hashmap, then update `max_count` accordingly.
5. After looping through all the rows, the result is the total number of rows minus the `max_count`. This gives the minimum number of crossed bricks.

## A solution in Python

```python
from collections import defaultdict

def least_bricks(wall):
    edge_count = defaultdict(int)
    max_count = 0

    for row in wall:
        edge_position = 0
        for i in range(len(row) - 1):
            edge_position += row[i]
            edge_count[edge_position] += 1
            max_count = max(max_count, edge_count[edge_position])

    return len(wall) - max_count
```
1. Create a hashmap `edge_count` to store the number of edges encountered at each position and initialize `max_count` to 0.
2. Loop through each row in the wall.
3. For each row, loop through its bricks (excluding the last brick) and keep track of the current brick edge position.
4. Increment the count for the current edge position in the hashmap, then update `max_count` accordingly.
5. After looping through all the rows, the result is the total number of rows minus the `max_count`. This gives the minimum number of crossed bricks.

## A solution in Javascript

```javascript
function leastBricks(wall) {
    const edgeCount = new Map();
    let maxCount = 0;

    for (const row of wall) {
        let edgePosition = 0;
        for (let i = 0; i < row.length - 1; ++i) {
            edgePosition += row[i];
            edgeCount.set(edgePosition, (edgeCount.get(edgePosition) || 0) + 1);
            maxCount = Math.max(maxCount, edgeCount.get(edgePosition));
        }
    }

    return wall.length - maxCount;
}
```
1. Create a hashmap `edge_count` to store the number of edges encountered at each position and initialize `max_count` to 0.
2. Loop through each row in the wall.
3. For each row, loop through its bricks (excluding the last brick) and keep track of the current brick edge position.
4. Increment the count for the current edge position in the hashmap, then update `max_count` accordingly.
5. After looping through all the rows, the result is the total number of rows minus the `max_count`. This gives the minimum number of crossed bricks.


# Split Concatenated Strings

- slug: split-concatenated-strings
- difficulty: Medium

You are given an array of strings `strs`. You could concatenate these strings together into a loop, where for each string, you could choose to reverse it or not. Among all the possible loops

Return _the lexicographically largest string after cutting the loop, which will make the looped string into a regular one_.

Specifically, to find the lexicographically largest string, you need to experience two phases:

1.  Concatenate all the strings into a loop, where you can reverse some strings or not and connect them in the same order as given.
2.  Cut and make one breakpoint in any place of the loop, which will make the looped string into a regular one starting from the character at the cutpoint.

And your job is to find the lexicographically largest one among all the possible regular strings.

**Example 1:**

**Input:** strs = \[ "abc ", "xyz "\]
**Output:**  "zyxcba "
**Explanation:** You can get the looped string  "-abcxyz- ",  "-abczyx- ",  "-cbaxyz- ",  "-cbazyx- ", where '-' represents the looped status.
The answer string came from the fourth looped one, where you could cut from the middle character 'a' and get  "zyxcba ".

**Example 2:**

**Input:** strs = \[ "abc "\]
**Output:**  "cba "

**Constraints:**

*   `1 <= strs.length <= 1000`
*   `1 <= strs[i].length <= 1000`
*   `1 <= sum(strs[i].length) <= 1000`
*   `strs[i]` consists of lowercase English letters.

## A solution in Java

```java
import java.util.*;

public String splitLoopedString(String[] strs) {
    String ans = "", cur = "";
    for (String s : strs) {
        String rev = new StringBuilder(s).reverse().toString();
        cur += (s.compareTo(rev) > 0) ? s : rev;
    }

    for (int i = 0, k = 0; i < strs.length; i++) {
        String rev = new StringBuilder(strs[i]).reverse().toString();
        for (String xstr : Arrays.asList(strs[i], rev)) {
            for (int j = 0; j < xstr.length(); j++) {
                String t = xstr.substring(j) + cur.substring(k + xstr.length()) + cur.substring(0, k) + xstr.substring(0, j);
                ans = ans.compareTo(t) > 0 ? ans : t;
            }
        }
        k += strs[i].length();
    }
    return ans;
}
```
The algorithm finds the lexicographically largest string in two steps. First, it concatenates all input strings into one looped string, choosing to use either the original string or its reverse for each string, based on which one is lexicographically larger. This way the looped string contains the maximum possible characters.

After creating the looped string, it iterates through all possible breakpoints in the loop. For each breakpoint, it constructs a regular string by moving the characters from the breakpoint to the end of the loop to the beginning of the new regular string, and checks whether the newly constructed string is lexicographically larger than the current maximum string. If it is, it updates the maximum string.

The time complexity of this algorithm is O(N*L^2) where N is the number of strings, and L is the length of the strings. This is because, in the worst case, the algorithm iterates through all strings (N), all possible breakpoints (L), and all characters of the string (L).

## A solution in C++

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

std::string splitLoopedString(std::vector<std::string>& strs) {
    std::string ans;
    std::string cur;
    for (auto &s : strs) {
        std::string rev(s.rbegin(), s.rend());
        cur += std::max(s, rev);
    }

    for (size_t i = 0, k = 0; i < strs.size(); ++i) {
        std::string rev(strs[i].rbegin(), strs[i].rend());
        for (auto &xstr : {strs[i], rev}) {
            for (size_t j = 0; j < xstr.size(); ++j) {
                std::string t = xstr.substr(j) + cur.substr(k + xstr.size()) + cur.substr(0, k) + xstr.substr(0, j);
                ans = std::max(ans, t);
            }
        }
        k += strs[i].size();
    }
    return ans;
}
```
The algorithm finds the lexicographically largest string in two steps. First, it concatenates all input strings into one looped string, choosing to use either the original string or its reverse for each string, based on which one is lexicographically larger. This way the looped string contains the maximum possible characters.

After creating the looped string, it iterates through all possible breakpoints in the loop. For each breakpoint, it constructs a regular string by moving the characters from the breakpoint to the end of the loop to the beginning of the new regular string, and checks whether the newly constructed string is lexicographically larger than the current maximum string. If it is, it updates the maximum string.

The time complexity of this algorithm is O(N*L^2) where N is the number of strings, and L is the length of the strings. This is because, in the worst case, the algorithm iterates through all strings (N), all possible breakpoints (L), and all characters of the string (L).

## A solution in Python

```python
def splitLoopedString(strs):
    ans = ''
    cur = ''.join(max(s, s[::-1]) for s in strs)

    for i, s in enumerate(strs):
        for xstr in (s, s[::-1]):
            for j in range(len(xstr)):
                t = xstr[j:] + cur[len(xstr):] + cur[:len(xstr)] + xstr[:j]
                ans = max(ans, t)
        cur = cur[len(s):] + cur[:len(s)]

    return ans
```
The algorithm finds the lexicographically largest string in two steps. First, it concatenates all input strings into one looped string, choosing to use either the original string or its reverse for each string, based on which one is lexicographically larger. This way the looped string contains the maximum possible characters.

After creating the looped string, it iterates through all possible breakpoints in the loop. For each breakpoint, it constructs a regular string by moving the characters from the breakpoint to the end of the loop to the beginning of the new regular string, and checks whether the newly constructed string is lexicographically larger than the current maximum string. If it is, it updates the maximum string.

The time complexity of this algorithm is O(N*L^2) where N is the number of strings, and L is the length of the strings. This is because, in the worst case, the algorithm iterates through all strings (N), all possible breakpoints (L), and all characters of the string (L).

## A solution in Javascript

```javascript
function splitLoopedString(strs) {
    let ans = "", cur = "";
    strs.forEach(s => {
        const rev = s.split('').reverse().join('');
        cur += s > rev ? s : rev;
    });

    for (let i = 0, k = 0; i < strs.length; i++) {
        let rev = strs[i].split('').reverse().join('');
        [strs[i], rev].forEach(xstr => {
            for (let j = 0; j < xstr.length; j++) {
                let t = xstr.slice(j) + cur.slice(k + xstr.length) + cur.slice(0, k) + xstr.slice(0, j);
                ans = ans > t ? ans : t;
            }
        });
        k += strs[i].length;
    }
    return ans;
}
```
The algorithm finds the lexicographically largest string in two steps. First, it concatenates all input strings into one looped string, choosing to use either the original string or its reverse for each string, based on which one is lexicographically larger. This way the looped string contains the maximum possible characters.

After creating the looped string, it iterates through all possible breakpoints in the loop. For each breakpoint, it constructs a regular string by moving the characters from the breakpoint to the end of the loop to the beginning of the new regular string, and checks whether the newly constructed string is lexicographically larger than the current maximum string. If it is, it updates the maximum string.

The time complexity of this algorithm is O(N*L^2) where N is the number of strings, and L is the length of the strings. This is because, in the worst case, the algorithm iterates through all strings (N), all possible breakpoints (L), and all characters of the string (L).