# Remove Duplicates from Sorted List II

- slug: remove-duplicates-from-sorted-list-ii
- difficulty: Medium

Given the `head` of a sorted linked list, _delete all nodes that have duplicate numbers, leaving only distinct numbers from the original list_. Return _the linked list **sorted** as well_.

**Example 1:**

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

**Example 2:**

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

**Constraints:**

*   The number of nodes in the list is in the range `[0, 300]`.
*   `-100 <= Node.val <= 100`
*   The list is guaranteed to be **sorted** in ascending order.

## A solution in Java

```java
class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public ListNode deleteDuplicates(ListNode head) {
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode prev = dummy, curr = head;
    while (curr != null) {
        while (curr.next != null && curr.val == curr.next.val)
            curr = curr.next;
        if (prev.next == curr)
            prev = prev.next;
        else
            prev.next = curr.next;
        curr = curr.next;
    }
    return dummy.next;
}
```
The algorithm uses a dummy node to simplify the handling of the head node of the linked list. We declare two pointers: `prev` and `curr` which are pointers to the previous and current nodes, respectively.

The algorithm iterates through the list with the current pointer. If the current node's value is equal to the next node's value, we continue moving the current pointer along the duplicate values. Once we reach the end of duplicates, we check if the previous node's next pointer is pointing to the current node. If it is, it means there were no duplicates (prev and curr are consecutive), so we move the `prev` pointer to the current node. Otherwise, we set `prev.next` to `curr.next` to skip the duplicates.

Finally, we move the current pointer to the next node, and repeat the process. The resulting list will have all duplicates removed, and the changes will persist as the dummy node is used to reference the head of the modified list.

## A solution in C++

```cpp
class ListNode {
public:
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(nullptr) {}
};

ListNode* deleteDuplicates(ListNode* head) {
    ListNode dummy(0);
    dummy.next = head;
    ListNode *prev = &dummy, *curr = head;
    while (curr) {
        while (curr->next && curr->val == curr->next->val)
            curr = curr->next;
        if (prev->next == curr)
            prev = prev->next;
        else
            prev->next = curr->next;
        curr = curr->next;
    }
    return dummy.next;
}
```
The algorithm uses a dummy node to simplify the handling of the head node of the linked list. We declare two pointers: `prev` and `curr` which are pointers to the previous and current nodes, respectively.

The algorithm iterates through the list with the current pointer. If the current node's value is equal to the next node's value, we continue moving the current pointer along the duplicate values. Once we reach the end of duplicates, we check if the previous node's next pointer is pointing to the current node. If it is, it means there were no duplicates (prev and curr are consecutive), so we move the `prev` pointer to the current node. Otherwise, we set `prev.next` to `curr.next` to skip the duplicates.

Finally, we move the current pointer to the next node, and repeat the process. The resulting list will have all duplicates removed, and the changes will persist as the dummy node is used to reference the head of the modified list.

## A solution in Python

```python
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

def deleteDuplicates(head):
    dummy = ListNode(0)
    dummy.next = head
    prev, curr = dummy, head
    while curr:
        while curr.next and curr.val == curr.next.val:
            curr = curr.next
        if prev.next == curr:
            prev = prev.next
        else:
            prev.next = curr.next
        curr = curr.next
    return dummy.next
```
The algorithm uses a dummy node to simplify the handling of the head node of the linked list. We declare two pointers: `prev` and `curr` which are pointers to the previous and current nodes, respectively.

The algorithm iterates through the list with the current pointer. If the current node's value is equal to the next node's value, we continue moving the current pointer along the duplicate values. Once we reach the end of duplicates, we check if the previous node's next pointer is pointing to the current node. If it is, it means there were no duplicates (prev and curr are consecutive), so we move the `prev` pointer to the current node. Otherwise, we set `prev.next` to `curr.next` to skip the duplicates.

Finally, we move the current pointer to the next node, and repeat the process. The resulting list will have all duplicates removed, and the changes will persist as the dummy node is used to reference the head of the modified list.

## A solution in Javascript

```javascript
class ListNode {
    constructor(val=0, next=null) {
        this.val = val;
        this.next = next;
    }
}

function deleteDuplicates(head) {
    const dummy = new ListNode(0);
    dummy.next = head;
    let prev = dummy, curr = head;
    while (curr) {
        while (curr.next && curr.val === curr.next.val) {
            curr = curr.next;
        }
        if (prev.next === curr) {
            prev = prev.next;
        } else {
            prev.next = curr.next;
        }
        curr = curr.next;
    }
    return dummy.next;
}
```
The algorithm uses a dummy node to simplify the handling of the head node of the linked list. We declare two pointers: `prev` and `curr` which are pointers to the previous and current nodes, respectively.

The algorithm iterates through the list with the current pointer. If the current node's value is equal to the next node's value, we continue moving the current pointer along the duplicate values. Once we reach the end of duplicates, we check if the previous node's next pointer is pointing to the current node. If it is, it means there were no duplicates (prev and curr are consecutive), so we move the `prev` pointer to the current node. Otherwise, we set `prev.next` to `curr.next` to skip the duplicates.

Finally, we move the current pointer to the next node, and repeat the process. The resulting list will have all duplicates removed, and the changes will persist as the dummy node is used to reference the head of the modified list.


# Remove Duplicates from Sorted List

- slug: remove-duplicates-from-sorted-list
- difficulty: Easy

Given the `head` of a sorted linked list, _delete all duplicates such that each element appears only once_. Return _the linked list **sorted** as well_.

**Example 1:**

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

**Example 2:**

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

**Constraints:**

*   The number of nodes in the list is in the range `[0, 300]`.
*   `-100 <= Node.val <= 100`
*   The list is guaranteed to be **sorted** in ascending order.

## A solution in Java

```java
public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) { val = x; }
}

public ListNode deleteDuplicates(ListNode head) {
    ListNode current = head;
    while (current != null && current.next != null) {
        if (current.next.val == current.val) {
            current.next = current.next.next;
        } else {
            current = current.next;
        }
    }
    return head;
}
```
The algorithm to delete all duplicates in a sorted linked list simply iterates through the list and compares the value of the current node with the value of the next. If both values are the same, it means that there is a duplicate, so the current node's "next" pointer is updated to point to the node after the duplicate. If the values are different, the algorithm continues iterating to the next node. The process continues until reaching the end of the list. Since the linked list is already sorted, this algorithm guarantees that duplicates will appear consecutively, allowing for their removal in linear time.

## A solution in C++

```cpp
struct ListNode {
    int val;
    ListNode* next;
    ListNode(int x) : val(x), next(nullptr) {}
};

ListNode* deleteDuplicates(ListNode* head) {
    ListNode* current = head;
    while (current && current->next) {
        if (current->next->val == current->val) {
            ListNode* temp = current->next;
            current->next = temp->next;
            delete temp;
        } else {
            current = current->next;
        }
    }
    return head;
}
```
The algorithm to delete all duplicates in a sorted linked list simply iterates through the list and compares the value of the current node with the value of the next. If both values are the same, it means that there is a duplicate, so the current node's "next" pointer is updated to point to the node after the duplicate. If the values are different, the algorithm continues iterating to the next node. The process continues until reaching the end of the list. Since the linked list is already sorted, this algorithm guarantees that duplicates will appear consecutively, allowing for their removal in linear time.

## A solution in Python

```python
class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def delete_duplicates(head):
    current = head
    while current and current.next:
        if current.next.val == current.val:
            current.next = current.next.next
        else:
            current = current.next
    return head
```
The algorithm to delete all duplicates in a sorted linked list simply iterates through the list and compares the value of the current node with the value of the next. If both values are the same, it means that there is a duplicate, so the current node's "next" pointer is updated to point to the node after the duplicate. If the values are different, the algorithm continues iterating to the next node. The process continues until reaching the end of the list. Since the linked list is already sorted, this algorithm guarantees that duplicates will appear consecutively, allowing for their removal in linear time.

## A solution in Javascript

```javascript
class ListNode {
    constructor(val, next = null) {
        this.val = val;
        this.next = next;
    }
}

function deleteDuplicates(head) {
    let current = head;
    while (current && current.next) {
        if (current.next.val === current.val) {
            current.next = current.next.next;
        } else {
            current = current.next;
        }
    }
    return head;
}
```
The algorithm to delete all duplicates in a sorted linked list simply iterates through the list and compares the value of the current node with the value of the next. If both values are the same, it means that there is a duplicate, so the current node's "next" pointer is updated to point to the node after the duplicate. If the values are different, the algorithm continues iterating to the next node. The process continues until reaching the end of the list. Since the linked list is already sorted, this algorithm guarantees that duplicates will appear consecutively, allowing for their removal in linear time.


# Largest Rectangle in Histogram

- slug: largest-rectangle-in-histogram
- difficulty: Hard

Given an array of integers `heights` representing the histogram's bar height where the width of each bar is `1`, return _the area of the largest rectangle in the histogram_.

**Example 1:**

**Input:** heights = \[2,1,5,6,2,3\]
**Output:** 10
**Explanation:** The above is a histogram where width of each bar is 1.
The largest rectangle is shown in the red area, which has an area = 10 units.

**Example 2:**

**Input:** heights = \[2,4\]
**Output:** 4

**Constraints:**

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

## A solution in Java

```java
public int largestRectangleArea(int[] heights) {
    Stack<Integer> stack = new Stack<>();
    int max_area = 0;
    for (int i = 0; i <= heights.length; i++) {
        int height = (i == heights.length) ? 0 : heights[i];
        while (!stack.isEmpty() && heights[stack.peek()] > height) {
            int h = heights[stack.pop()];
            int w = stack.isEmpty() ? i : i - stack.peek() - 1;
            max_area = Math.max(max_area, h * w);
        }
        stack.push(i);
    }
    return max_area;
}
```
The algorithm utilizes a stack to keep track of the indices of the heights array. It starts iterating through the array, appending a zero at the end to ensure the last bar is considered. When a higher bar is found, it is pushed onto the stack, and if a lower bar is found, it calculates the area of the bar under the current top of the stack considering the width between the current bar and the next lowest bar in the stack, storing the highest area found.

This algorithm has a time complexity of O(n) as it iterates through the heights only once, resulting in optimal performance.

## A solution in C++

```cpp
int largestRectangleArea(vector<int>& heights) {
    heights.push_back(0);
    stack<int> s;
    int max_area = 0;
    for (int i = 0; i < heights.size(); i++) {
        while (!s.empty() && heights[s.top()] > heights[i]) {
            int height = heights[s.top()];
            s.pop();
            int width = s.empty() ? i : i - s.top() - 1;
            max_area = max(max_area, height * width);
        }
        s.push(i);
    }
    return max_area;
}
```
The algorithm utilizes a stack to keep track of the indices of the heights array. It starts iterating through the array, appending a zero at the end to ensure the last bar is considered. When a higher bar is found, it is pushed onto the stack, and if a lower bar is found, it calculates the area of the bar under the current top of the stack considering the width between the current bar and the next lowest bar in the stack, storing the highest area found.

This algorithm has a time complexity of O(n) as it iterates through the heights only once, resulting in optimal performance.

## A solution in Python

```python
def largestRectangleArea(heights):
    stack = []
    max_area = 0
    for i, h in enumerate(heights + [0]):
        while stack and heights[stack[-1]] > h:
            height = heights[stack.pop()]
            width = i if not stack else i - stack[-1] - 1
            max_area = max(max_area, height * width)
        stack.append(i)
    return max_area
```
The algorithm utilizes a stack to keep track of the indices of the heights array. It starts iterating through the array, appending a zero at the end to ensure the last bar is considered. When a higher bar is found, it is pushed onto the stack, and if a lower bar is found, it calculates the area of the bar under the current top of the stack considering the width between the current bar and the next lowest bar in the stack, storing the highest area found.

This algorithm has a time complexity of O(n) as it iterates through the heights only once, resulting in optimal performance.

## A solution in Javascript

```javascript
function largestRectangleArea(heights) {
    let stack = [];
    let max_area = 0;
    heights.push(0);
    for (let i = 0; i < heights.length; i++) {
        while (stack.length > 0 && heights[stack[stack.length - 1]] > heights[i]) {
            let height = heights[stack.pop()];
            let width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1;
            max_area = Math.max(max_area, height * width);
        }
        stack.push(i);
    }
    return max_area;
}
```
The algorithm utilizes a stack to keep track of the indices of the heights array. It starts iterating through the array, appending a zero at the end to ensure the last bar is considered. When a higher bar is found, it is pushed onto the stack, and if a lower bar is found, it calculates the area of the bar under the current top of the stack considering the width between the current bar and the next lowest bar in the stack, storing the highest area found.

This algorithm has a time complexity of O(n) as it iterates through the heights only once, resulting in optimal performance.


# Maximal Rectangle

- slug: maximal-rectangle
- difficulty: Hard

Given a `rows x cols` binary `matrix` filled with `0`'s and `1`'s, find the largest rectangle containing only `1`'s and return _its area_.

**Example 1:**

**Input:** matrix = \[\[ "1 ", "0 ", "1 ", "0 ", "0 "\],\[ "1 ", "0 ", "1 ", "1 ", "1 "\],\[ "1 ", "1 ", "1 ", "1 ", "1 "\],\[ "1 ", "0 ", "0 ", "1 ", "0 "\]\]
**Output:** 6
**Explanation:** The maximal rectangle is shown in the above picture.

**Example 2:**

**Input:** matrix = \[\[ "0 "\]\]
**Output:** 0

**Example 3:**

**Input:** matrix = \[\[ "1 "\]\]
**Output:** 1

**Constraints:**

*   `rows == matrix.length`
*   `cols == matrix[i].length`
*   `1 <= row, cols <= 200`
*   `matrix[i][j]` is `'0'` or `'1'`.

## A solution in Java

```java
import java.util.Stack;

public int maximalRectangle(char[][] matrix) {
    if (matrix.length == 0) return 0;

    int m = matrix.length;
    int n = matrix[0].length;
    int[] height = new int[n + 1];
    int maxArea = 0;

    for (int i = 0; i < m; ++i) {
        Stack<Integer> s = new Stack<>();
        for (int j = 0; j <= n; ++j) {
            if (j < n) {
                height[j] = matrix[i][j] == '1' ? height[j] + 1 : 0;
            }
            while (!s.empty() && height[j] < height[s.peek()]) {
                int h = height[s.pop()];
                int w = s.empty() ? j : j - s.peek() - 1;
                maxArea = Math.max(maxArea, h * w);
            }
            s.push(j);
        }
    }

    return maxArea;
}
```
The algorithm uses a stack to keep track of indices of increasing heights. The height-array is updated every row to add the height of the previous row if the cell value is '1', else it is set to 0. Every time a smaller height is encountered than the top of the stack, we pop the top of the stack and calculate the area using that height (popped value) and the width (current index minus the index below the top of the stack minus 1), updating maxArea with the new maximum value.

This is done for all the rows of the matrix, and finally, the maxArea is returned.

## A solution in C++

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

int maximalRectangle(vector<vector<char>>& matrix) {
    if (matrix.empty()) return 0;

    int m = matrix.size();
    int n = matrix[0].size();
    vector<int> height(n + 1, 0);
    int maxArea = 0;

    for (int i = 0; i < m; ++i) {
        stack<int> s;
        for (int j = 0; j <= n; ++j) {
            if (j < n) {
                height[j] = matrix[i][j] == '1' ? height[j] + 1 : 0;
            }
            while (!s.empty() && height[j] < height[s.top()]) {
                int h = height[s.top()];
                s.pop();
                int w = s.empty() ? j : j - s.top() - 1;
                maxArea = max(maxArea, h * w);
            }
            s.push(j);
        }
    }

    return maxArea;
}
```
The algorithm uses a stack to keep track of indices of increasing heights. The height-array is updated every row to add the height of the previous row if the cell value is '1', else it is set to 0. Every time a smaller height is encountered than the top of the stack, we pop the top of the stack and calculate the area using that height (popped value) and the width (current index minus the index below the top of the stack minus 1), updating maxArea with the new maximum value.

This is done for all the rows of the matrix, and finally, the maxArea is returned.

## A solution in Python

```python
def maximalRectangle(matrix):
    if not matrix:
        return 0

    m = len(matrix)
    n = len(matrix[0])
    height = [0] * (n + 1)
    max_area = 0

    for i in range(m):
        s = []
        for j in range(n + 1):
            if j < n:
                height[j] = height[j] + 1 if matrix[i][j] == '1' else 0
            while s and height[j] < height[s[-1]]:
                h = height[s.pop()]
                w = j if not s else j - s[-1] - 1
                max_area = max(max_area, h * w)
            s.append(j)

    return max_area
```
The algorithm uses a stack to keep track of indices of increasing heights. The height-array is updated every row to add the height of the previous row if the cell value is '1', else it is set to 0. Every time a smaller height is encountered than the top of the stack, we pop the top of the stack and calculate the area using that height (popped value) and the width (current index minus the index below the top of the stack minus 1), updating maxArea with the new maximum value.

This is done for all the rows of the matrix, and finally, the maxArea is returned.

## A solution in Javascript

```javascript
function maximalRectangle(matrix) {
    if (!matrix.length) return 0;

    let m = matrix.length;
    let n = matrix[0].length;
    let height = Array(n + 1).fill(0);
    let maxArea = 0;

    for (let i = 0; i < m; i++) {
        let s = [];
        for (let j = 0; j <= n; j++) {
            if (j < n) {
                height[j] = matrix[i][j] === '1' ? height[j] + 1 : 0;
            }
            while (s.length && height[j] < height[s[s.length - 1]]) {
                let h = height[s.pop()];
                let w = !s.length ? j : j - s[s.length - 1] - 1;
                maxArea = Math.max(maxArea, h * w);
            }
            s.push(j);
        }
    }

    return maxArea;
}
```
The algorithm uses a stack to keep track of indices of increasing heights. The height-array is updated every row to add the height of the previous row if the cell value is '1', else it is set to 0. Every time a smaller height is encountered than the top of the stack, we pop the top of the stack and calculate the area using that height (popped value) and the width (current index minus the index below the top of the stack minus 1), updating maxArea with the new maximum value.

This is done for all the rows of the matrix, and finally, the maxArea is returned.


# Partition List

- slug: partition-list
- difficulty: Medium

Given the `head` of a linked list and a value `x`, partition it such that all nodes **less than** `x` come before nodes **greater than or equal** to `x`.

You should **preserve** the original relative order of the nodes in each of the two partitions.

**Example 1:**

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

**Example 2:**

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

**Constraints:**

*   The number of nodes in the list is in the range `[0, 200]`.
*   `-100 <= Node.val <= 100`
*   `-200 <= x <= 200`

## A solution in Java

```java
public class ListNode {
    int val;
    ListNode next;
    ListNode(int x) {
        val = x;
        next = null;
    }
}

public ListNode partition(ListNode head, int x) {
    ListNode less_head = new ListNode(0);
    ListNode more_head = new ListNode(0);
    ListNode less_ptr = less_head, more_ptr = more_head;

    while (head != null) {
        if (head.val < x) {
            less_ptr.next = head;
            less_ptr = head;
        } else {
            more_ptr.next = head;
            more_ptr = head;
        }
        head = head.next;
    }

    less_ptr.next = more_head.next;
    more_ptr.next = null;

    return less_head.next;
}
```
1. Create two new ListNodes: less_head and more_head. These will act as head pointers for partitions of nodes that have values less than x and greater than or equal to x.
2. Initialize two pointers, less_ptr and more_ptr, to point to the dummy head nodes just created.
3. Iterate through the original linked list. For each node, compare its value with the given x.
4. If the current node's value is less than x, append it to the partition pointed by less_ptr, and move less_ptr forward.
5. If the current node's value is greater than or equal to x, append it to the partition pointed by more_ptr, and move more_ptr forward.
6. Perform the above steps until the entire linked list has been traversed.
7. After iterating through the linked list, connect the end of the less partition with the start of the more partition.
8. Move the more_ptr to the end of its partition setting the its next to null.
9. Return the head of the new partitioned linked list, which is less_head.next

## A solution in C++

```cpp
class ListNode {
public:
    int val;
    ListNode *next;
    ListNode(int x) : val(x), next(NULL) {}
};

ListNode* partition(ListNode* head, int x) {
    ListNode less_head(0), more_head(0);
    ListNode *less_ptr = &less_head, *more_ptr = &more_head;

    while (head) {
        if (head->val < x) {
            less_ptr->next = head;
            less_ptr = head;
        } else {
            more_ptr->next = head;
            more_ptr = head;
        }
        head = head->next;
    }

    less_ptr->next = more_head.next;
    more_ptr->next = NULL;

    return less_head.next;
}
```
1. Create two new ListNodes: less_head and more_head. These will act as head pointers for partitions of nodes that have values less than x and greater than or equal to x.
2. Initialize two pointers, less_ptr and more_ptr, to point to the dummy head nodes just created.
3. Iterate through the original linked list. For each node, compare its value with the given x.
4. If the current node's value is less than x, append it to the partition pointed by less_ptr, and move less_ptr forward.
5. If the current node's value is greater than or equal to x, append it to the partition pointed by more_ptr, and move more_ptr forward.
6. Perform the above steps until the entire linked list has been traversed.
7. After iterating through the linked list, connect the end of the less partition with the start of the more partition.
8. Move the more_ptr to the end of its partition setting the its next to null.
9. Return the head of the new partitioned linked list, which is less_head.next

## A solution in Python

```python
class ListNode:
    def __init__(self, x):
        self.val = x
        self.next = None

def partition(head, x):
    less_head = ListNode(0)
    more_head = ListNode(0)
    less_ptr, more_ptr = less_head, more_head

    while head:
        if head.val < x:
            less_ptr.next = head
            less_ptr = head
        else:
            more_ptr.next = head
            more_ptr = head
        head = head.next

    less_ptr.next = more_head.next
    more_ptr.next = None

    return less_head.next
```
1. Create two new ListNodes: less_head and more_head. These will act as head pointers for partitions of nodes that have values less than x and greater than or equal to x.
2. Initialize two pointers, less_ptr and more_ptr, to point to the dummy head nodes just created.
3. Iterate through the original linked list. For each node, compare its value with the given x.
4. If the current node's value is less than x, append it to the partition pointed by less_ptr, and move less_ptr forward.
5. If the current node's value is greater than or equal to x, append it to the partition pointed by more_ptr, and move more_ptr forward.
6. Perform the above steps until the entire linked list has been traversed.
7. After iterating through the linked list, connect the end of the less partition with the start of the more partition.
8. Move the more_ptr to the end of its partition setting the its next to null.
9. Return the head of the new partitioned linked list, which is less_head.next

## A solution in Javascript

```javascript
class ListNode {
    constructor(x) {
        this.val = x;
        this.next = null;
    }
}

function partition(head, x) {
    let less_head = new ListNode(0);
    let more_head = new ListNode(0);
    let less_ptr = less_head, more_ptr = more_head;

    while (head !== null) {
        if (head.val < x) {
            less_ptr.next = head;
            less_ptr = head;
        } else {
            more_ptr.next = head;
            more_ptr = head;
        }
        head = head.next;
    }

    less_ptr.next = more_head.next;
    more_ptr.next = null;

    return less_head.next;
}
```
1. Create two new ListNodes: less_head and more_head. These will act as head pointers for partitions of nodes that have values less than x and greater than or equal to x.
2. Initialize two pointers, less_ptr and more_ptr, to point to the dummy head nodes just created.
3. Iterate through the original linked list. For each node, compare its value with the given x.
4. If the current node's value is less than x, append it to the partition pointed by less_ptr, and move less_ptr forward.
5. If the current node's value is greater than or equal to x, append it to the partition pointed by more_ptr, and move more_ptr forward.
6. Perform the above steps until the entire linked list has been traversed.
7. After iterating through the linked list, connect the end of the less partition with the start of the more partition.
8. Move the more_ptr to the end of its partition setting the its next to null.
9. Return the head of the new partitioned linked list, which is less_head.next


# Scramble String

- slug: scramble-string
- difficulty: Hard

We can scramble a string s to get a string t using the following algorithm:

1.  If the length of the string is 1, stop.
2.  If the length of the string is > 1, do the following:
    *   Split the string into two non-empty substrings at a random index, i.e., if the string is `s`, divide it to `x` and `y` where `s = x + y`.
    *   **Randomly** decide to swap the two substrings or to keep them in the same order. i.e., after this step, `s` may become `s = x + y` or `s = y + x`.
    *   Apply step 1 recursively on each of the two substrings `x` and `y`.

Given two strings `s1` and `s2` of **the same length**, return `true` if `s2` is a scrambled string of `s1`, otherwise, return `false`.

**Example 1:**

**Input:** s1 =  "great ", s2 =  "rgeat "
**Output:** true
**Explanation:** One possible scenario applied on s1 is:
 "great " -->  "gr/eat " // divide at random index.
 "gr/eat " -->  "gr/eat " // random decision is not to swap the two substrings and keep them in order.
 "gr/eat " -->  "g/r / e/at " // apply the same algorithm recursively on both substrings. divide at random index each of them.
 "g/r / e/at " -->  "r/g / e/at " // random decision was to swap the first substring and to keep the second substring in the same order.
 "r/g / e/at " -->  "r/g / e/ a/t " // again apply the algorithm recursively, divide  "at " to  "a/t ".
 "r/g / e/ a/t " -->  "r/g / e/ a/t " // random decision is to keep both substrings in the same order.
The algorithm stops now, and the result string is  "rgeat " which is s2.
As one possible scenario led s1 to be scrambled to s2, we return true.

**Example 2:**

**Input:** s1 =  "abcde ", s2 =  "caebd "
**Output:** false

**Example 3:**

**Input:** s1 =  "a ", s2 =  "a "
**Output:** true

**Constraints:**

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

## A solution in Java

```java
public boolean isScramble(String s1, String s2) {
    if (s1.equals(s2)) return true;
    if (sorted(s1).equals(sorted(s2)) == false) return false;

    for (int i = 1; i < s1.length(); i++) {
        if (isScramble(s1.substring(0, i), s2.substring(0, i)) && isScramble(s1.substring(i), s2.substring(i)))
            return true;
        if (isScramble(s1.substring(0, i), s2.substring(s2.length() - i)) && isScramble(s1.substring(i), s2.substring(0, s2.length() - i)))
            return true;
    }
    return false;
}

private String sorted(String s) {
    char[] chars = s.toCharArray();
    Arrays.sort(chars);
    return new String(chars);
}
```
The algorithm works by recursively dividing the strings into smaller substrings and checking if the substrings from s1 can be rearranged into the corresponding substrings of s2. The base case is when both strings (s1, and s2) are equal. If the lengths of the strings are different or the characters are different, then the function returns false. Then, we iterate through the length of strings, dividing the strings into smaller substrings and checking if these substrings can be rearranged to form the scrambled string. We check for both possible arrangements of the substrings, i.e., same order and reverse order, invoking the same function recursively for each combination.

## A solution in C++

```cpp
bool isScramble(string s1, string s2) {
    if (s1 == s2) return true;
    if (s1.size() != s2.size() || sort(s1.begin(), s1.end()) != sort(s2.begin(), s2.end())) return false;

    for (int i = 1; i < s1.size(); i++) {
        if (isScramble(s1.substr(0, i), s2.substr(0, i)) && isScramble(s1.substr(i), s2.substr(i)))
            return true;
        if (isScramble(s1.substr(0, i), s2.substr(s2.size() - i)) && isScramble(s1.substr(i), s2.substr(0, s2.size() - i)))
            return true;
    }
    return false;
}
```
The algorithm works by recursively dividing the strings into smaller substrings and checking if the substrings from s1 can be rearranged into the corresponding substrings of s2. The base case is when both strings (s1, and s2) are equal. If the lengths of the strings are different or the characters are different, then the function returns false. Then, we iterate through the length of strings, dividing the strings into smaller substrings and checking if these substrings can be rearranged to form the scrambled string. We check for both possible arrangements of the substrings, i.e., same order and reverse order, invoking the same function recursively for each combination.

## A solution in Python

```python
def isScramble(s1: str, s2: str) -> bool:
    if s1 == s2:
        return True
    if len(s1) != len(s2) or sorted(s1) != sorted(s2):
        return False

    for i in range(1, len(s1)):
        if (isScramble(s1[:i], s2[:i]) and isScramble(s1[i:], s2[i:])) or \
           (isScramble(s1[:i], s2[-i:]) and isScramble(s1[i:], s2[:-i])):
            return True
    return False
```
The algorithm works by recursively dividing the strings into smaller substrings and checking if the substrings from s1 can be rearranged into the corresponding substrings of s2. The base case is when both strings (s1, and s2) are equal. If the lengths of the strings are different or the characters are different, then the function returns false. Then, we iterate through the length of strings, dividing the strings into smaller substrings and checking if these substrings can be rearranged to form the scrambled string. We check for both possible arrangements of the substrings, i.e., same order and reverse order, invoking the same function recursively for each combination.

## A solution in Javascript

```javascript
function isScramble(s1, s2) {
    if (s1 === s2) return true;
    if (s1.length !== s2.length || sorted(s1) !== sorted(s2)) return false;

    for (let i = 1; i < s1.length; i++) {
        if ((isScramble(s1.slice(0, i), s2.slice(0, i)) && isScramble(s1.slice(i), s2.slice(i))) ||
            (isScramble(s1.slice(0, i), s2.slice(s2.length - i)) && isScramble(s1.slice(i), s2.slice(0, s2.length - i))))
            return true;
    }
    return false;
}

function sorted(s) {
    return s.split('').sort().join('');
}
```
The algorithm works by recursively dividing the strings into smaller substrings and checking if the substrings from s1 can be rearranged into the corresponding substrings of s2. The base case is when both strings (s1, and s2) are equal. If the lengths of the strings are different or the characters are different, then the function returns false. Then, we iterate through the length of strings, dividing the strings into smaller substrings and checking if these substrings can be rearranged to form the scrambled string. We check for both possible arrangements of the substrings, i.e., same order and reverse order, invoking the same function recursively for each combination.


# Merge Sorted Array

- slug: merge-sorted-array
- difficulty: Easy

You are given two integer arrays `nums1` and `nums2`, sorted in **non-decreasing order**, and two integers `m` and `n`, representing the number of elements in `nums1` and `nums2` respectively.

**Merge** `nums1` and `nums2` into a single array sorted in **non-decreasing order**.

The final sorted array should not be returned by the function, but instead be _stored inside the array_ `nums1`. To accommodate this, `nums1` has a length of `m + n`, where the first `m` elements denote the elements that should be merged, and the last `n` elements are set to `0` and should be ignored. `nums2` has a length of `n`.

**Example 1:**

**Input:** nums1 = \[1,2,3,0,0,0\], m = 3, nums2 = \[2,5,6\], n = 3
**Output:** \[1,2,2,3,5,6\]
**Explanation:** The arrays we are merging are \[1,2,3\] and \[2,5,6\].
The result of the merge is \[1,2,2,3,5,6\] with the underlined elements coming from nums1.

**Example 2:**

**Input:** nums1 = \[1\], m = 1, nums2 = \[\], n = 0
**Output:** \[1\]
**Explanation:** The arrays we are merging are \[1\] and \[\].
The result of the merge is \[1\].

**Example 3:**

**Input:** nums1 = \[0\], m = 0, nums2 = \[1\], n = 1
**Output:** \[1\]
**Explanation:** The arrays we are merging are \[\] and \[1\].
The result of the merge is \[1\].
Note that because m = 0, there are no elements in nums1. The 0 is only there to ensure the merge result can fit in nums1.

**Constraints:**

*   `nums1.length == m + n`
*   `nums2.length == n`
*   `0 <= m, n <= 200`
*   `1 <= m + n <= 200`
*   `-109 <= nums1[i], nums2[j] <= 109`

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

## A solution in Java

```java
public void merge(int[] nums1, int m, int[] nums2, int n) {
    int i = m - 1, j = n - 1, k = m + n - 1;
    while (i >= 0 && j >= 0) {
        if (nums1[i] > nums2[j])
            nums1[k--] = nums1[i--];
        else
            nums1[k--] = nums2[j--];
    }
    while (j >= 0) {
        nums1[k--] = nums2[j--];
    }
}
```
We use a two-pointer approach to merge nums1 and nums2 in reverse order. Initialize three pointers i, j, and k pointing to the last elements of nums1, nums2, and the merged nums1 array respectively.

Iterate in a while loop until i and j are both less than 0. Compare the values of nums1[i] and nums2[j]. If nums1[i] is greater, assign nums1[i] at position k in nums1, decrement i and k. Otherwise, assign nums2[j] at position k in nums1, and decrement j and k. This process continues for all elements in nums2.

After the loop, if there are still elements remaining in nums2 (j >= 0), copy the remaining elements of nums2 to nums1. In this way, we merge nums1 and nums2 in non-decreasing order.

## A solution in C++

```cpp
void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) {
    int i = m - 1, j = n - 1, k = m + n - 1;
    while (i >= 0 && j >= 0) {
        if (nums1[i] > nums2[j])
            nums1[k--] = nums1[i--];
        else
            nums1[k--] = nums2[j--];
    }
    while (j >= 0) {
        nums1[k--] = nums2[j--];
    }
}
```
We use a two-pointer approach to merge nums1 and nums2 in reverse order. Initialize three pointers i, j, and k pointing to the last elements of nums1, nums2, and the merged nums1 array respectively.

Iterate in a while loop until i and j are both less than 0. Compare the values of nums1[i] and nums2[j]. If nums1[i] is greater, assign nums1[i] at position k in nums1, decrement i and k. Otherwise, assign nums2[j] at position k in nums1, and decrement j and k. This process continues for all elements in nums2.

After the loop, if there are still elements remaining in nums2 (j >= 0), copy the remaining elements of nums2 to nums1. In this way, we merge nums1 and nums2 in non-decreasing order.

## A solution in Python

```python
def merge(nums1, m, nums2, n):
    i, j, k = m - 1, n - 1, m + n - 1
    while i >= 0 and j >= 0:
        if nums1[i] > nums2[j]:
            nums1[k] = nums1[i]
            i -= 1
        else:
            nums1[k] = nums2[j]
            j -= 1
        k -= 1
    while j >= 0:
        nums1[k] = nums2[j]
        k -= 1
        j -= 1
```
We use a two-pointer approach to merge nums1 and nums2 in reverse order. Initialize three pointers i, j, and k pointing to the last elements of nums1, nums2, and the merged nums1 array respectively.

Iterate in a while loop until i and j are both less than 0. Compare the values of nums1[i] and nums2[j]. If nums1[i] is greater, assign nums1[i] at position k in nums1, decrement i and k. Otherwise, assign nums2[j] at position k in nums1, and decrement j and k. This process continues for all elements in nums2.

After the loop, if there are still elements remaining in nums2 (j >= 0), copy the remaining elements of nums2 to nums1. In this way, we merge nums1 and nums2 in non-decreasing order.

## A solution in Javascript

```javascript
function merge(nums1, m, nums2, n) {
    let i = m - 1, j = n - 1, k = m + n - 1;
    while (i >= 0 && j >= 0) {
        if (nums1[i] > nums2[j])
            nums1[k--] = nums1[i--];
        else
            nums1[k--] = nums2[j--];
    }
    while (j >= 0) {
        nums1[k--] = nums2[j--];
    }
}
```
We use a two-pointer approach to merge nums1 and nums2 in reverse order. Initialize three pointers i, j, and k pointing to the last elements of nums1, nums2, and the merged nums1 array respectively.

Iterate in a while loop until i and j are both less than 0. Compare the values of nums1[i] and nums2[j]. If nums1[i] is greater, assign nums1[i] at position k in nums1, decrement i and k. Otherwise, assign nums2[j] at position k in nums1, and decrement j and k. This process continues for all elements in nums2.

After the loop, if there are still elements remaining in nums2 (j >= 0), copy the remaining elements of nums2 to nums1. In this way, we merge nums1 and nums2 in non-decreasing order.


# Gray Code

- slug: gray-code
- difficulty: Medium

An **n-bit gray code sequence** is a sequence of `2n` integers where:

*   Every integer is in the **inclusive** range `[0, 2n - 1]`,
*   The first integer is `0`,
*   An integer appears **no more than once** in the sequence,
*   The binary representation of every pair of **adjacent** integers differs by **exactly one bit**, and
*   The binary representation of the **first** and **last** integers differs by **exactly one bit**.

Given an integer `n`, return _any valid **n-bit gray code sequence**_.

**Example 1:**

**Input:** n = 2
**Output:** \[0,1,3,2\]
**Explanation:**
The binary representation of \[0,1,3,2\] is \[00,01,11,10\].
- 00 and 01 differ by one bit
- 01 and 11 differ by one bit
- 11 and 10 differ by one bit
- 10 and 00 differ by one bit
\[0,2,3,1\] is also a valid gray code sequence, whose binary representation is \[00,10,11,01\].
- 00 and 10 differ by one bit
- 10 and 11 differ by one bit
- 11 and 01 differ by one bit
- 01 and 00 differ by one bit

**Example 2:**

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

**Constraints:**

*   `1 <= n <= 16`

## A solution in Java

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

public List<Integer> grayCode(int n) {
    List<Integer> result = new ArrayList<>();
    for (int i = 0; i < (1 << n); i++) {
        result.add(i ^ (i >> 1));
    }
    return result;
}
```
The algorithm generates an n-bit gray code sequence by following the simple bitwise operation:

1. Loop through all numbers from 0 to 2^n - 1.
2. For each number i, calculate the gray code value by performing the bitwise XOR operation (i ^ (i >> 1))
3. Add the gray code value to the result list or vector.

The algorithm has a time complexity of O(2^n) which is the size of the output sequence. The space complexity is also O(2^n), as we store the sequence in a list or vector.

## A solution in C++

```cpp
#include <vector>

std::vector<int> grayCode(int n) {
    std::vector<int> result;
    for (int i = 0; i < (1 << n); i++) {
        result.push_back(i ^ (i >> 1));
    }
    return result;
}
```
The algorithm generates an n-bit gray code sequence by following the simple bitwise operation:

1. Loop through all numbers from 0 to 2^n - 1.
2. For each number i, calculate the gray code value by performing the bitwise XOR operation (i ^ (i >> 1))
3. Add the gray code value to the result list or vector.

The algorithm has a time complexity of O(2^n) which is the size of the output sequence. The space complexity is also O(2^n), as we store the sequence in a list or vector.

## A solution in Python

```python
def grayCode(n):
    result = []
    for i in range(1 << n):
        result.append(i ^ (i >> 1))
    return result
```
The algorithm generates an n-bit gray code sequence by following the simple bitwise operation:

1. Loop through all numbers from 0 to 2^n - 1.
2. For each number i, calculate the gray code value by performing the bitwise XOR operation (i ^ (i >> 1))
3. Add the gray code value to the result list or vector.

The algorithm has a time complexity of O(2^n) which is the size of the output sequence. The space complexity is also O(2^n), as we store the sequence in a list or vector.

## A solution in Javascript

```javascript
function grayCode(n) {
    const result = [];
    for (let i = 0; i < (1 << n); i++) {
        result.push(i ^ (i >> 1));
    }
    return result;
}
```
The algorithm generates an n-bit gray code sequence by following the simple bitwise operation:

1. Loop through all numbers from 0 to 2^n - 1.
2. For each number i, calculate the gray code value by performing the bitwise XOR operation (i ^ (i >> 1))
3. Add the gray code value to the result list or vector.

The algorithm has a time complexity of O(2^n) which is the size of the output sequence. The space complexity is also O(2^n), as we store the sequence in a list or vector.


# Subsets II

- slug: subsets-ii
- difficulty: Medium

Given an integer array `nums` that may contain duplicates, return _all possible_ _subsets_ _(the power set)_.

The solution set **must not** contain duplicate subsets. Return the solution in **any order**.

**Example 1:**

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

**Example 2:**

**Input:** nums = \[0\]
**Output:** \[\[\],\[0\]\]

**Constraints:**

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

## A solution in Java

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

public List<List<Integer>> subsetsWithDup(int[] nums) {
    Set<List<Integer>> result = new HashSet<>();
    Arrays.sort(nums);
    backtrack(nums, 0, new ArrayList<Integer>(), result);
    return new ArrayList<>(result);
}

private void backtrack(int[] nums, int index, List<Integer> subset, Set<List<Integer>> result) {
    result.add(new ArrayList<>(subset));
    for (int i = index; i < nums.length; i++) {
        subset.add(nums[i]);
        backtrack(nums, i + 1, subset, result);
        subset.remove(subset.size() - 1);
    }
}
```
The algorithm first sorts the given array, and then it generates all possible subsets. For each subset, it checks if it already exists in the result set. If not, it adds the subset to the result set.

The algorithm uses a backtracking approach. It starts with an empty subset and iteratively adds elements from the input array to the subset. It keeps track of the starting index to avoid creating duplicate subsets.

In the C++ and Java implementations, a `set` data structure is used to store unique subsets. In the Python implementation, Python's `set` is used along with itertools' `combinations` function to achieve the same result. In the JavaScript implementation, a `Set` object is used, but as it doesn't handle array comparisons properly, each subset is converted into a JSON string to compare the string representation of subsets.

At the end, the function returns the result set, converted into the desired format (list of lists or vector of vectors).

## A solution in C++

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

vector<vector<int>> subsetsWithDup(vector<int>& nums) {
    set<vector<int>> result;
    vector<int> subset;
    sort(nums.begin(), nums.end());
    backtrack(nums, 0, subset, result);
    return vector<vector<int>>(result.begin(), result.end());
}

void backtrack(vector<int>& nums, int index, vector<int>& subset, set<vector<int>>& result) {
    result.insert(subset);
    for (int i = index; i < nums.size(); i++) {
        subset.push_back(nums[i]);
        backtrack(nums, i + 1, subset, result);
        subset.pop_back();
    }
}
```
The algorithm first sorts the given array, and then it generates all possible subsets. For each subset, it checks if it already exists in the result set. If not, it adds the subset to the result set.

The algorithm uses a backtracking approach. It starts with an empty subset and iteratively adds elements from the input array to the subset. It keeps track of the starting index to avoid creating duplicate subsets.

In the C++ and Java implementations, a `set` data structure is used to store unique subsets. In the Python implementation, Python's `set` is used along with itertools' `combinations` function to achieve the same result. In the JavaScript implementation, a `Set` object is used, but as it doesn't handle array comparisons properly, each subset is converted into a JSON string to compare the string representation of subsets.

At the end, the function returns the result set, converted into the desired format (list of lists or vector of vectors).

## A solution in Python

```python
from itertools import combinations

def subsetsWithDup(nums):
    result = set()
    nums.sort()
    for i in range(len(nums) + 1):
        for combo in combinations(nums, i):
            result.add(combo)
    return list(result)
```
The algorithm first sorts the given array, and then it generates all possible subsets. For each subset, it checks if it already exists in the result set. If not, it adds the subset to the result set.

The algorithm uses a backtracking approach. It starts with an empty subset and iteratively adds elements from the input array to the subset. It keeps track of the starting index to avoid creating duplicate subsets.

In the C++ and Java implementations, a `set` data structure is used to store unique subsets. In the Python implementation, Python's `set` is used along with itertools' `combinations` function to achieve the same result. In the JavaScript implementation, a `Set` object is used, but as it doesn't handle array comparisons properly, each subset is converted into a JSON string to compare the string representation of subsets.

At the end, the function returns the result set, converted into the desired format (list of lists or vector of vectors).

## A solution in Javascript

```javascript
function subsetsWithDup(nums) {
  const result = new Set();
  nums.sort((a, b) => a - b);
  backtrack(nums, 0, [], result);
  return Array.from(result).map(item => Array.from(item));
}

function backtrack(nums, index, subset, result) {
  result.add(JSON.stringify(subset));
  for (let i = index; i < nums.length; i++) {
    subset.push(nums[i]);
    backtrack(nums, i + 1, subset, result);
    subset.pop();
  }
}
```
The algorithm first sorts the given array, and then it generates all possible subsets. For each subset, it checks if it already exists in the result set. If not, it adds the subset to the result set.

The algorithm uses a backtracking approach. It starts with an empty subset and iteratively adds elements from the input array to the subset. It keeps track of the starting index to avoid creating duplicate subsets.

In the C++ and Java implementations, a `set` data structure is used to store unique subsets. In the Python implementation, Python's `set` is used along with itertools' `combinations` function to achieve the same result. In the JavaScript implementation, a `Set` object is used, but as it doesn't handle array comparisons properly, each subset is converted into a JSON string to compare the string representation of subsets.

At the end, the function returns the result set, converted into the desired format (list of lists or vector of vectors).


# Decode Ways

- slug: decode-ways
- difficulty: Medium

A message containing letters from `A-Z` can be **encoded** into numbers using the following mapping:

'A' ->  "1 "
'B' ->  "2 "
...
'Z' ->  "26 "

To **decode** an encoded message, all the digits must be grouped then mapped back into letters using the reverse of the mapping above (there may be multiple ways). For example, `"11106 "` can be mapped into:

*   `"AAJF "` with the grouping `(1 1 10 6)`
*   `"KJF "` with the grouping `(11 10 6)`

Note that the grouping `(1 11 06)` is invalid because `"06 "` cannot be mapped into `'F'` since `"6 "` is different from `"06 "`.

Given a string `s` containing only digits, return _the **number** of ways to **decode** it_.

The test cases are generated so that the answer fits in a **32-bit** integer.

**Example 1:**

**Input:** s =  "12 "
**Output:** 2
**Explanation:**  "12 " could be decoded as  "AB " (1 2) or  "L " (12).

**Example 2:**

**Input:** s =  "226 "
**Output:** 3
**Explanation:**  "226 " could be decoded as  "BZ " (2 26),  "VF " (22 6), or  "BBF " (2 2 6).

**Example 3:**

**Input:** s =  "06 "
**Output:** 0
**Explanation:**  "06 " cannot be mapped to  "F " because of the leading zero ( "6 " is different from  "06 ").

**Constraints:**

*   `1 <= s.length <= 100`
*   `s` contains only digits and may contain leading zero(s).

## A solution in Java

```java
public int numDecodings(String s) {
    int n = s.length();
    int[] dp = new int[n + 1];
    dp[0] = 1;
    dp[1] = s.charAt(0) != '0' ? 1 : 0;

    for (int i = 2; i <= n; i++) {
        int oneDigit = Integer.parseInt(s.substring(i - 1, i));
        int twoDigits = Integer.parseInt(s.substring(i - 2, i));

        if (oneDigit >= 1)
            dp[i] += dp[i - 1];
        if (twoDigits >= 10 && twoDigits <= 26)
            dp[i] += dp[i - 2];
    }
    return dp[n];
}
```
We use dynamic programming (DP) to solve this problem. The `dp` array is of size `n+1`, where `n` is the length of the input string `s`. `dp[i]` stores the number of ways to decode the substring `s[0:i]`.

Initialize `dp[0]` to 1 because there is always one way to decode an empty string.

For each character in the string `s`, consider its corresponding one-digit and two-digits representations. If the one-digit representation is valid (>=1), we can increment `dp[i]` by `dp[i-1]`, which means one more way to decode the string by using the one-digit representation of the current character. If the two-digits representation is valid (>=10 and <=26), we can increment `dp[i]` by `dp[i-2]`, meaning one way to decode the string by using the two-digits representation of the current character.

After we finished iterating through the string `s`, `dp[n]` will store the number of ways to decode the entire string.

## A solution in C++

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

int numDecodings(std::string s) {
    int n = s.size();
    std::vector<int> dp(n + 1, 0);
    dp[0] = 1;
    dp[1] = s[0] != '0' ? 1 : 0;

    for (int i = 2; i <= n; ++i) {
        int oneDigit = stoi(s.substr(i - 1, 1));
        int twoDigits = stoi(s.substr(i - 2, 2));

        if (oneDigit >= 1)
            dp[i] += dp[i - 1];
        if (twoDigits >= 10 && twoDigits <= 26)
            dp[i] += dp[i - 2];
    }
    return dp[n];
}
```
We use dynamic programming (DP) to solve this problem. The `dp` array is of size `n+1`, where `n` is the length of the input string `s`. `dp[i]` stores the number of ways to decode the substring `s[0:i]`.

Initialize `dp[0]` to 1 because there is always one way to decode an empty string.

For each character in the string `s`, consider its corresponding one-digit and two-digits representations. If the one-digit representation is valid (>=1), we can increment `dp[i]` by `dp[i-1]`, which means one more way to decode the string by using the one-digit representation of the current character. If the two-digits representation is valid (>=10 and <=26), we can increment `dp[i]` by `dp[i-2]`, meaning one way to decode the string by using the two-digits representation of the current character.

After we finished iterating through the string `s`, `dp[n]` will store the number of ways to decode the entire string.

## A solution in Python

```python
def numDecodings(s: str) -> int:
    n = len(s)
    dp = [0] * (n + 1)
    dp[0] = 1
    dp[1] = 1 if s[0] != '0' else 0

    for i in range(2, n + 1):
        one_digit = int(s[i - 1:i])
        two_digits = int(s[i - 2:i])

        if one_digit >= 1:
            dp[i] += dp[i - 1]
        if two_digits >= 10 and two_digits <= 26:
            dp[i] += dp[i - 2]
    return dp[n]
```
We use dynamic programming (DP) to solve this problem. The `dp` array is of size `n+1`, where `n` is the length of the input string `s`. `dp[i]` stores the number of ways to decode the substring `s[0:i]`.

Initialize `dp[0]` to 1 because there is always one way to decode an empty string.

For each character in the string `s`, consider its corresponding one-digit and two-digits representations. If the one-digit representation is valid (>=1), we can increment `dp[i]` by `dp[i-1]`, which means one more way to decode the string by using the one-digit representation of the current character. If the two-digits representation is valid (>=10 and <=26), we can increment `dp[i]` by `dp[i-2]`, meaning one way to decode the string by using the two-digits representation of the current character.

After we finished iterating through the string `s`, `dp[n]` will store the number of ways to decode the entire string.

## A solution in Javascript

```javascript
var numDecodings = function(s) {
    const n = s.length;
    const dp = new Array(n + 1).fill(0);
    dp[0] = 1;
    dp[1] = s[0] !== '0' ? 1 : 0;

    for (let i = 2; i <= n; i++) {
        const oneDigit = parseInt(s.slice(i - 1, i), 10);
        const twoDigits = parseInt(s.slice(i - 2, i), 10);

        if (oneDigit >= 1)
            dp[i] += dp[i - 1];
        if (twoDigits >= 10 && twoDigits <= 26)
            dp[i] += dp[i - 2];
    }
    return dp[n];
};
```
We use dynamic programming (DP) to solve this problem. The `dp` array is of size `n+1`, where `n` is the length of the input string `s`. `dp[i]` stores the number of ways to decode the substring `s[0:i]`.

Initialize `dp[0]` to 1 because there is always one way to decode an empty string.

For each character in the string `s`, consider its corresponding one-digit and two-digits representations. If the one-digit representation is valid (>=1), we can increment `dp[i]` by `dp[i-1]`, which means one more way to decode the string by using the one-digit representation of the current character. If the two-digits representation is valid (>=10 and <=26), we can increment `dp[i]` by `dp[i-2]`, meaning one way to decode the string by using the two-digits representation of the current character.

After we finished iterating through the string `s`, `dp[n]` will store the number of ways to decode the entire string.


# Reverse Linked List II

- slug: reverse-linked-list-ii
- difficulty: Medium

Given the `head` of a singly linked list and two integers `left` and `right` where `left <= right`, reverse the nodes of the list from position `left` to position `right`, and return _the reversed list_.

**Example 1:**

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

**Example 2:**

**Input:** head = \[5\], left = 1, right = 1
**Output:** \[5\]

**Constraints:**

*   The number of nodes in the list is `n`.
*   `1 <= n <= 500`
*   `-500 <= Node.val <= 500`
*   `1 <= left <= right <= n`

**Follow up:** Could you do it in one pass?

## A solution in Java

```java
public ListNode reverseBetween(ListNode head, int left, int right) {
    if (head == null || left == right) return head;
    ListNode dummy = new ListNode(0);
    dummy.next = head;
    ListNode pre = dummy;
    for (int i = 1; i < left; ++i) pre = pre.next;
    ListNode cur = pre.next;
    for (int i = left; i < right; ++i) {
        ListNode t = cur.next;
        cur.next = t.next;
        t.next = pre.next;
        pre.next = t;
    }
    return dummy.next;
}
```
The algorithm creates a dummy node and connects it to the head of the linked list. It then iterates through the list, reversing the nodes from position `left` to `right`. It maintains pointers `pre` and `cur` to accomplish this. During each iteration, it temporarily stores the next node using a pointer `t`, then reverses the connections between the nodes.

This process is repeated for all languages; the only differences in implementation are syntax-related.

In C++, use pointers and "->" to access the next node. In Java and Python, we use dot notation to access the next attribute. In JavaScript, we also use dot notation and "===" for equality comparison between left and right.

## A solution in C++

```cpp
ListNode* reverseBetween(ListNode* head, int left, int right) {
    if (!head || left == right) return head;
    ListNode dummy(0);
    dummy.next = head;
    ListNode* pre = &dummy;
    for (int i = 1; i < left; ++i) pre = pre->next;
    ListNode* cur = pre->next;
    for (int i = left; i < right; ++i) {
        ListNode* t = cur->next;
        cur->next = t->next;
        t->next = pre->next;
        pre->next = t;
    }
    return dummy.next;
}
```
The algorithm creates a dummy node and connects it to the head of the linked list. It then iterates through the list, reversing the nodes from position `left` to `right`. It maintains pointers `pre` and `cur` to accomplish this. During each iteration, it temporarily stores the next node using a pointer `t`, then reverses the connections between the nodes.

This process is repeated for all languages; the only differences in implementation are syntax-related.

In C++, use pointers and "->" to access the next node. In Java and Python, we use dot notation to access the next attribute. In JavaScript, we also use dot notation and "===" for equality comparison between left and right.

## A solution in Python

```python
def reverseBetween(self, head: Optional[ListNode], left: int, right: int) -> Optional[ListNode]:
    if not head or left == right:
        return head
    dummy = ListNode(0)
    dummy.next = head
    pre = dummy
    for _ in range(left - 1):
        pre = pre.next
    cur = pre.next
    for _ in range(left, right):
        t = cur.next
        cur.next = t.next
        t.next = pre.next
        pre.next = t
    return dummy.next
```
The algorithm creates a dummy node and connects it to the head of the linked list. It then iterates through the list, reversing the nodes from position `left` to `right`. It maintains pointers `pre` and `cur` to accomplish this. During each iteration, it temporarily stores the next node using a pointer `t`, then reverses the connections between the nodes.

This process is repeated for all languages; the only differences in implementation are syntax-related.

In C++, use pointers and "->" to access the next node. In Java and Python, we use dot notation to access the next attribute. In JavaScript, we also use dot notation and "===" for equality comparison between left and right.

## A solution in Javascript

```javascript
function reverseBetween(head, left, right) {
    if (!head || left === right) return head;
    const dummy = new ListNode(0);
    dummy.next = head;
    let pre = dummy;
    for (let i = 1; i < left; ++i) pre = pre.next;
    let cur = pre.next;
    for (let i = left; i < right; ++i) {
        const t = cur.next;
        cur.next = t.next;
        t.next = pre.next;
        pre.next = t;
    }
    return dummy.next;
}
```
The algorithm creates a dummy node and connects it to the head of the linked list. It then iterates through the list, reversing the nodes from position `left` to `right`. It maintains pointers `pre` and `cur` to accomplish this. During each iteration, it temporarily stores the next node using a pointer `t`, then reverses the connections between the nodes.

This process is repeated for all languages; the only differences in implementation are syntax-related.

In C++, use pointers and "->" to access the next node. In Java and Python, we use dot notation to access the next attribute. In JavaScript, we also use dot notation and "===" for equality comparison between left and right.


# Restore IP Addresses

- slug: restore-ip-addresses
- difficulty: Medium

A **valid IP address** consists of exactly four integers separated by single dots. Each integer is between `0` and `255` (**inclusive**) and cannot have leading zeros.

*   For example, `"0.1.2.201 "` and `"192.168.1.1 "` are **valid** IP addresses, but `"0.011.255.245 "`, `"192.168.1.312 "` and `"192.168@1.1 "` are **invalid** IP addresses.

Given a string `s` containing only digits, return _all possible valid IP addresses that can be formed by inserting dots into_ `s`. You are **not** allowed to reorder or remove any digits in `s`. You may return the valid IP addresses in **any** order.

**Example 1:**

**Input:** s =  "25525511135 "
**Output:** \[ "255.255.11.135 ", "255.255.111.35 "\]

**Example 2:**

**Input:** s =  "0000 "
**Output:** \[ "0.0.0.0 "\]

**Example 3:**

**Input:** s =  "101023 "
**Output:** \[ "1.0.10.23 ", "1.0.102.3 ", "10.1.0.23 ", "10.10.2.3 ", "101.0.2.3 "\]

**Constraints:**

*   `1 <= s.length <= 20`
*   `s` consists of digits only.

## A solution in Java

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

public List<String> restoreIpAddresses(String s) {
    List<String> result = new ArrayList<>();
    dfs(s, 0, "", result, 0);
    return result;
}

private void dfs(String s, int start, String ip, List<String> result, int part) {
    if (part == 4 && start == s.length()) {
        result.add(ip.substring(0, ip.length() - 1));
        return;
    }
    if (part == 4 || start >= s.length()) return;

    int num = 0;
    for (int i = start; i < s.length(); i++) {
        num = num * 10 + (s.charAt(i) - '0');
        if (num > 255) break;
        dfs(s, i + 1, ip + s.charAt(i) + ".", result, part + 1);
        if (num == 0) break;
    }
}
```
We use a Depth-First Search algorithm to explore all possible configurations of the IP address. The function takes in the input string (s), the starting index (start), the partially constructed IP address (ip), and the current part count (part).

In each call to the function, we try to add one part to the IP address. If 4 parts have been added and we have reached the end of the input string, we have found a valid IP address and add it to the result list.

The algorithm iterates through the string s, starting at the current index. It keeps track of the current number (0-255) being constructed by multiplying the current number by 10 and adding the current digit. If the current number is greater than 255, we break the iteration.

We then call the dfs function recursively, with the current index incremented by one, the current IP appended with the current character and a dot, and incrementing part by 1. If the current number is 0 (which indicates a leading zero), we also break the iteration.

This process is repeated for all valid parts and combinations, eventually forming all possible valid IP addresses.

## A solution in C++

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

vector<string> restore_ip_address(string s) {
    vector<string> result;
    string ip;
    dfs(result, s, ip, 0, 0);
    return result;
}

void dfs(vector<string>& result, string s, string ip, int start, int part) {
    if (part == 4 && start == s.size()) {
        ip.pop_back();
        result.push_back(ip);
        return;
    }
    if (part == 4 || start == s.size()) return;

    int num = 0;
    for (int i = start; i < s.size(); i++) {
        num = num * 10 + (s[i] - '0');
        if (num > 255) break;
        ip += s[i];
        dfs(result, s, ip + '.', i + 1, part + 1);
        if (num == 0) break;
    }
}
```
We use a Depth-First Search algorithm to explore all possible configurations of the IP address. The function takes in the input string (s), the starting index (start), the partially constructed IP address (ip), and the current part count (part).

In each call to the function, we try to add one part to the IP address. If 4 parts have been added and we have reached the end of the input string, we have found a valid IP address and add it to the result list.

The algorithm iterates through the string s, starting at the current index. It keeps track of the current number (0-255) being constructed by multiplying the current number by 10 and adding the current digit. If the current number is greater than 255, we break the iteration.

We then call the dfs function recursively, with the current index incremented by one, the current IP appended with the current character and a dot, and incrementing part by 1. If the current number is 0 (which indicates a leading zero), we also break the iteration.

This process is repeated for all valid parts and combinations, eventually forming all possible valid IP addresses.

## A solution in Python

```python
def restore_ip_addresses(s):
    def dfs(s, start, ip, result, part):
        if part == 4 and start == len(s):
            result.append(ip[:-1])
            return
        if part == 4 or start >= len(s):
            return

        num = 0
        for i in range(start, len(s)):
            num = num * 10 + int(s[i])
            if num > 255:
                break
            dfs(s, i + 1, ip + s[i] + ".", result, part + 1)
            if num == 0:
                break

    result = []
    dfs(s, 0, "", result, 0)
    return result
```
We use a Depth-First Search algorithm to explore all possible configurations of the IP address. The function takes in the input string (s), the starting index (start), the partially constructed IP address (ip), and the current part count (part).

In each call to the function, we try to add one part to the IP address. If 4 parts have been added and we have reached the end of the input string, we have found a valid IP address and add it to the result list.

The algorithm iterates through the string s, starting at the current index. It keeps track of the current number (0-255) being constructed by multiplying the current number by 10 and adding the current digit. If the current number is greater than 255, we break the iteration.

We then call the dfs function recursively, with the current index incremented by one, the current IP appended with the current character and a dot, and incrementing part by 1. If the current number is 0 (which indicates a leading zero), we also break the iteration.

This process is repeated for all valid parts and combinations, eventually forming all possible valid IP addresses.

## A solution in Javascript

```javascript
function restoreIpAddresses(s) {
    const result = [];
    dfs(s, 0, "", result, 0);
    return result;
}

function dfs(s, start, ip, result, part) {
    if (part === 4 && start === s.length) {
        result.push(ip.slice(0, -1));
        return;
    }
    if (part === 4 || start >= s.length) return;

    let num = 0;
    for (let i = start; i < s.length; i++) {
        num = num * 10 + parseInt(s[i]);
        if (num > 255) break;
        dfs(s, i + 1, ip + s[i] + ".", result, part + 1);
        if (num === 0) break;
    }
}
```
We use a Depth-First Search algorithm to explore all possible configurations of the IP address. The function takes in the input string (s), the starting index (start), the partially constructed IP address (ip), and the current part count (part).

In each call to the function, we try to add one part to the IP address. If 4 parts have been added and we have reached the end of the input string, we have found a valid IP address and add it to the result list.

The algorithm iterates through the string s, starting at the current index. It keeps track of the current number (0-255) being constructed by multiplying the current number by 10 and adding the current digit. If the current number is greater than 255, we break the iteration.

We then call the dfs function recursively, with the current index incremented by one, the current IP appended with the current character and a dot, and incrementing part by 1. If the current number is 0 (which indicates a leading zero), we also break the iteration.

This process is repeated for all valid parts and combinations, eventually forming all possible valid IP addresses.


# Binary Tree Inorder Traversal

- slug: binary-tree-inorder-traversal
- difficulty: Easy

Given the `root` of a binary tree, return _the inorder traversal of its nodes' values_.

**Example 1:**

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

**Example 2:**

**Input:** root = \[\]
**Output:** \[\]

**Example 3:**

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

**Constraints:**

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

**Follow up:** Recursive solution is trivial, could you do it iteratively?

## A solution in Java

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

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

public List<Integer> inorderTraversal(TreeNode root) {
    List<Integer> result = new ArrayList<>();
    inorderTraversalHelper(root, result);
    return result;
}

private void inorderTraversalHelper(TreeNode root, List<Integer> result) {
    if (root == null) {
        return;
    }
    inorderTraversalHelper(root.left, result);
    result.add(root.val);
    inorderTraversalHelper(root.right, result);
}
```
The algorithm simply performs an inorder traversal on the given binary tree. An inorder traversal goes as follows:

1. Traverse the left subtree, and call the function recursively for the left child.
2. Visit the root.
3. Traverse the right subtree, and call the function recursively for the right child.

This process is implemented by defining a helper function (`inorderTraversalHelper`) that takes a node and a `result` list (or vector in C++), and appends the node's value to the `result` list according to the inorder traversal order. The main `inorderTraversal` function initializes the result list and calls the helper function with the root of the tree. At the end, `inorderTraversal` returns the result list containing the values of the nodes in inorder traversal order.

## A solution in C++

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

class TreeNode {
public:
    int val;
    TreeNode *left;
    TreeNode *right;
};

void inorderTraversalHelper(TreeNode* root, vector<int>& result) {
    if (!root) return;
    inorderTraversalHelper(root->left, result);
    result.push_back(root->val);
    inorderTraversalHelper(root->right, result);
}

vector<int> inorderTraversal(TreeNode* root){
    vector<int> result;
    inorderTraversalHelper(root, result);
    return result;
}
```
The algorithm simply performs an inorder traversal on the given binary tree. An inorder traversal goes as follows:

1. Traverse the left subtree, and call the function recursively for the left child.
2. Visit the root.
3. Traverse the right subtree, and call the function recursively for the right child.

This process is implemented by defining a helper function (`inorderTraversalHelper`) that takes a node and a `result` list (or vector in C++), and appends the node's value to the `result` list according to the inorder traversal order. The main `inorderTraversal` function initializes the result list and calls the helper function with the root of the tree. At the end, `inorderTraversal` returns the result list containing the values of the nodes in inorder traversal order.

## 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 inorderTraversalHelper(root, result):
    if not root:
        return
    inorderTraversalHelper(root.left, result)
    result.append(root.val)
    inorderTraversalHelper(root.right, result)

def inorderTraversal(root):
    result = []
    inorderTraversalHelper(root, result)
    return result
```
The algorithm simply performs an inorder traversal on the given binary tree. An inorder traversal goes as follows:

1. Traverse the left subtree, and call the function recursively for the left child.
2. Visit the root.
3. Traverse the right subtree, and call the function recursively for the right child.

This process is implemented by defining a helper function (`inorderTraversalHelper`) that takes a node and a `result` list (or vector in C++), and appends the node's value to the `result` list according to the inorder traversal order. The main `inorderTraversal` function initializes the result list and calls the helper function with the root of the tree. At the end, `inorderTraversal` returns the result list containing the values of the nodes in inorder traversal order.

## A solution in Javascript

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

function inorderTraversalHelper(root, result) {
    if (!root) return;
    inorderTraversalHelper(root.left, result);
    result.push(root.val);
    inorderTraversalHelper(root.right, result);
}

function inorderTraversal(root) {
    let result = [];
    inorderTraversalHelper(root, result);
    return result;
}
```
The algorithm simply performs an inorder traversal on the given binary tree. An inorder traversal goes as follows:

1. Traverse the left subtree, and call the function recursively for the left child.
2. Visit the root.
3. Traverse the right subtree, and call the function recursively for the right child.

This process is implemented by defining a helper function (`inorderTraversalHelper`) that takes a node and a `result` list (or vector in C++), and appends the node's value to the `result` list according to the inorder traversal order. The main `inorderTraversal` function initializes the result list and calls the helper function with the root of the tree. At the end, `inorderTraversal` returns the result list containing the values of the nodes in inorder traversal order.


# Unique Binary Search Trees II

- slug: unique-binary-search-trees-ii
- difficulty: Medium

Given an integer `n`, return _all the structurally unique **BST'**s (binary search trees), which has exactly_ `n` _nodes of unique values from_ `1` _to_ `n`. Return the answer in **any order**.

**Example 1:**

**Input:** n = 3
**Output:** \[\[1,null,2,null,3\],\[1,null,3,2\],\[2,1,3\],\[3,1,null,null,2\],\[3,2,null,1\]\]

**Example 2:**

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

**Constraints:**

*   `1 <= n <= 8`

## A solution in Java

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

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

class Solution {
    public List<TreeNode> generateTrees(int start, int end) {
        List<TreeNode> trees = new ArrayList<>();
        if (start > end) {
            trees.add(null);
            return trees;
        }

        for (int i = start; i <= end; i++) {
            List<TreeNode> leftSubtrees = generateTrees(start, i - 1);
            List<TreeNode> rightSubtrees = generateTrees(i + 1, end);

            for (TreeNode left : leftSubtrees) {
                for (TreeNode right : rightSubtrees) {
                    TreeNode newNode = new TreeNode(i);
                    newNode.left = left;
                    newNode.right = right;
                    trees.add(newNode);
                }
            }
        }

        return trees;
    }

    public List<TreeNode> generateTrees(int n) {
        if (n == 0) {
            return new ArrayList<TreeNode>();
        }
        return generateTrees(1, n);
    }
}
```
The algorithm is a recursive one. It starts by iterating from `start` to `end`. For every value `i`, it generates left and right subtrees by calling itself recursively with the modified start and end values,  i.e., `generateTrees(start, i - 1)` for the left subtree and `generateTrees(i + 1, end)` for the right subtree. It then creates new nodes with the value `i` and combinations of left and right subtrees, adding the newly created nodes to the `trees` list.

Finally, the function returns the list of trees when the recursive calls end.

## A solution in C++

```cpp
#include <vector>

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

std::vector<TreeNode*> generateTrees(int start, int end) {
    std::vector<TreeNode*> trees;
    if (start > end) {
        trees.push_back(nullptr);
        return trees;
    }

    for (int i = start; i <= end; i++) {
        std::vector<TreeNode*> leftSubtrees = generateTrees(start, i - 1);
        std::vector<TreeNode*> rightSubtrees = generateTrees(i + 1, end);

        for (TreeNode* left : leftSubtrees) {
            for (TreeNode* right : rightSubtrees) {
                TreeNode* newNode = new TreeNode(i);
                newNode->left = left;
                newNode->right = right;
                trees.push_back(newNode);
            }
        }
    }

    return trees;
}

std::vector<TreeNode*> generateTrees(int n) {
    if (n == 0) {
        return std::vector<TreeNode*>();
    }
    return generateTrees(1, n);
}
```
The algorithm is a recursive one. It starts by iterating from `start` to `end`. For every value `i`, it generates left and right subtrees by calling itself recursively with the modified start and end values,  i.e., `generateTrees(start, i - 1)` for the left subtree and `generateTrees(i + 1, end)` for the right subtree. It then creates new nodes with the value `i` and combinations of left and right subtrees, adding the newly created nodes to the `trees` list.

Finally, the function returns the list of trees when the recursive calls end.

## 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 generate_trees(start, end):
    trees = []
    if start > end:
        trees.append(None)
        return trees

    for i in range(start, end + 1):
        left_subtrees = generate_trees(start, i - 1)
        right_subtrees = generate_trees(i + 1, end)

        for left in left_subtrees:
            for right in right_subtrees:
                new_node = TreeNode(i)
                new_node.left = left
                new_node.right = right
                trees.append(new_node)

    return trees

def generate_trees(n):
    if n == 0:
        return []
    return generate_trees(1, n)
```
The algorithm is a recursive one. It starts by iterating from `start` to `end`. For every value `i`, it generates left and right subtrees by calling itself recursively with the modified start and end values,  i.e., `generateTrees(start, i - 1)` for the left subtree and `generateTrees(i + 1, end)` for the right subtree. It then creates new nodes with the value `i` and combinations of left and right subtrees, adding the newly created nodes to the `trees` list.

Finally, the function returns the list of trees when the recursive calls end.

## A solution in Javascript

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

function generateTrees(start, end) {
    const trees = [];
    if (start > end) {
        trees.push(null);
        return trees;
    }

    for (let i = start; i <= end; i++) {
        const leftSubtrees = generateTrees(start, i - 1);
        const rightSubtrees = generateTrees(i + 1, end);

        for (const left of leftSubtrees) {
            for (const right of rightSubtrees) {
                const newNode = new TreeNode(i);
                newNode.left = left;
                newNode.right = right;
                trees.push(newNode);
            }
        }
    }

    return trees;
}

function generateTrees(n) {
    if (n === 0) {
        return [];
    }
    return generateTrees(1, n);
}
```
The algorithm is a recursive one. It starts by iterating from `start` to `end`. For every value `i`, it generates left and right subtrees by calling itself recursively with the modified start and end values,  i.e., `generateTrees(start, i - 1)` for the left subtree and `generateTrees(i + 1, end)` for the right subtree. It then creates new nodes with the value `i` and combinations of left and right subtrees, adding the newly created nodes to the `trees` list.

Finally, the function returns the list of trees when the recursive calls end.


# Unique Binary Search Trees

- slug: unique-binary-search-trees
- difficulty: Medium

Given an integer `n`, return _the number of structurally unique **BST'**s (binary search trees) which has exactly_ `n` _nodes of unique values from_ `1` _to_ `n`.

**Example 1:**

**Input:** n = 3
**Output:** 5

**Example 2:**

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

**Constraints:**

*   `1 <= n <= 19`

## A solution in Java

```java
public int numTrees(int n) {
    int[] dp = new int[n + 1];
    dp[0] = 1;
    dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        for (int j = 0; j < i; j++) {
            dp[i] += dp[j] * dp[i - j - 1];
        }
    }
    return dp[n];
}
```
The algorithm is based on dynamic programming. We create an array `dp` of length `n + 1`, with `dp[0]` and `dp[1]` equal to 1, which corresponds to the cases of 0 and 1 node respectively. Next, we iterate from 2 to `n`, and for each value `i`, we iterate from 0 to `i` and accumulate `dp[j] * dp[i - j - 1]` in `dp[i]`. This process represents the number of structurally unique BSTs for the left subtree and right subtree for each possible node arrangement of the BST. At the end, `dp[n]` represents the number of structurally unique BSTs with precisely n nodes.

## A solution in C++

```cpp
int numTrees(int n) {
    vector<int> dp(n + 1, 0);
    dp[0] = dp[1] = 1;
    for (int i = 2; i <= n; i++) {
        for (int j = 0; j < i; j++) {
            dp[i] += dp[j] * dp[i - j - 1];
        }
    }
    return dp[n];
}
```
The algorithm is based on dynamic programming. We create an array `dp` of length `n + 1`, with `dp[0]` and `dp[1]` equal to 1, which corresponds to the cases of 0 and 1 node respectively. Next, we iterate from 2 to `n`, and for each value `i`, we iterate from 0 to `i` and accumulate `dp[j] * dp[i - j - 1]` in `dp[i]`. This process represents the number of structurally unique BSTs for the left subtree and right subtree for each possible node arrangement of the BST. At the end, `dp[n]` represents the number of structurally unique BSTs with precisely n nodes.

## A solution in Python

```python
def numTrees(n):
    dp = [0] * (n + 1)
    dp[0] = 1
    dp[1] = 1
    for i in range(2, n + 1):
        for j in range(i):
            dp[i] += dp[j] * dp[i - j - 1]
    return dp[n]
```
The algorithm is based on dynamic programming. We create an array `dp` of length `n + 1`, with `dp[0]` and `dp[1]` equal to 1, which corresponds to the cases of 0 and 1 node respectively. Next, we iterate from 2 to `n`, and for each value `i`, we iterate from 0 to `i` and accumulate `dp[j] * dp[i - j - 1]` in `dp[i]`. This process represents the number of structurally unique BSTs for the left subtree and right subtree for each possible node arrangement of the BST. At the end, `dp[n]` represents the number of structurally unique BSTs with precisely n nodes.

## A solution in Javascript

```javascript
function numTrees(n) {
    let dp = new Array(n + 1).fill(0);
    dp[0] = 1;
    dp[1] = 1;
    for (let i = 2; i <= n; i++) {
        for (let j = 0; j < i; j++) {
            dp[i] += dp[j] * dp[i - j - 1];
        }
    }
    return dp[n];
}
```
The algorithm is based on dynamic programming. We create an array `dp` of length `n + 1`, with `dp[0]` and `dp[1]` equal to 1, which corresponds to the cases of 0 and 1 node respectively. Next, we iterate from 2 to `n`, and for each value `i`, we iterate from 0 to `i` and accumulate `dp[j] * dp[i - j - 1]` in `dp[i]`. This process represents the number of structurally unique BSTs for the left subtree and right subtree for each possible node arrangement of the BST. At the end, `dp[n]` represents the number of structurally unique BSTs with precisely n nodes.


# Interleaving String

- slug: interleaving-string
- difficulty: Medium

Given strings `s1`, `s2`, and `s3`, find whether `s3` is formed by an **interleaving** of `s1` and `s2`.

An **interleaving** of two strings `s` and `t` is a configuration where `s` and `t` are divided into `n` and `m` substrings respectively, such that:

*   `s = s1 + s2 + ... + sn`
*   `t = t1 + t2 + ... + tm`
*   `|n - m| <= 1`
*   The **interleaving** is `s1 + t1 + s2 + t2 + s3 + t3 + ...` or `t1 + s1 + t2 + s2 + t3 + s3 + ...`

**Note:** `a + b` is the concatenation of strings `a` and `b`.

**Example 1:**

**Input:** s1 =  "aabcc ", s2 =  "dbbca ", s3 =  "aadbbcbcac "
**Output:** true
**Explanation:** One way to obtain s3 is:
Split s1 into s1 =  "aa " +  "bc " +  "c ", and s2 into s2 =  "dbbc " +  "a ".
Interleaving the two splits, we get  "aa " +  "dbbc " +  "bc " +  "a " +  "c " =  "aadbbcbcac ".
Since s3 can be obtained by interleaving s1 and s2, we return true.

**Example 2:**

**Input:** s1 =  "aabcc ", s2 =  "dbbca ", s3 =  "aadbbbaccc "
**Output:** false
**Explanation:** Notice how it is impossible to interleave s2 with any other string to obtain s3.

**Example 3:**

**Input:** s1 =  " ", s2 =  " ", s3 =  " "
**Output:** true

**Constraints:**

*   `0 <= s1.length, s2.length <= 100`
*   `0 <= s3.length <= 200`
*   `s1`, `s2`, and `s3` consist of lowercase English letters.

**Follow up:** Could you solve it using only `O(s2.length)` additional memory space?

## A solution in Java

```java
public boolean isInterleave(String s1, String s2, String s3) {
    int m = s1.length(), n = s2.length();
    if (m + n != s3.length()) return false;

    boolean[][] dp = new boolean[m + 1][n + 1];
    dp[0][0] = true;
    for (int i = 1; i <= m; i++)
        dp[i][0] = dp[i - 1][0] && s1.charAt(i - 1) == s3.charAt(i - 1);
    for (int j = 1; j <= n; j++)
        dp[0][j] = dp[0][j - 1] && s2.charAt(j - 1) == s3.charAt(j - 1);

    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            dp[i][j] = (dp[i - 1][j] && s1.charAt(i - 1) == s3.charAt(i + j - 1)) ||
                       (dp[i][j - 1] && s2.charAt(j - 1) == s3.charAt(i + j - 1));
        }
    }

    return dp[m][n];
}
```
We use a dynamic programming approach (2D DP) to solve this problem. The algorithm checks whether the s3[position] is equal to s1 or s2 in the same dp[position]. If so, we take the value of the previous dp[i-1] or dp[j-1] accordingly if the characters match. For the base case, we start with initializing dp[0][0] to true since two empty strings can form an empty s3.

At the end of the iterations, the last element in the dp matrix (i.e. dp[m][n]) will represent whether s3 can be formed by an interleaving of s1 and s2.

## A solution in C++

```cpp
bool isInterleave(string s1, string s2, string s3) {
    int m = s1.length(), n = s2.length();
    if (m + n != s3.length()) return false;

    vector<vector<bool>> dp(m + 1, vector<bool>(n + 1, false));
    dp[0][0] = true;
    for (int i = 1; i <= m; i++)
        dp[i][0] = dp[i - 1][0] && s1[i - 1] == s3[i - 1];
    for (int j = 1; j <= n; j++)
        dp[0][j] = dp[0][j - 1] && s2[j - 1] == s3[j - 1];

    for (int i = 1; i <= m; i++) {
        for (int j = 1; j <= n; j++) {
            dp[i][j] = (dp[i - 1][j] && s1[i - 1] == s3[i + j - 1]) ||
                       (dp[i][j - 1] && s2[j - 1] == s3[i + j - 1]);
        }
    }

    return dp[m][n];
}
```
We use a dynamic programming approach (2D DP) to solve this problem. The algorithm checks whether the s3[position] is equal to s1 or s2 in the same dp[position]. If so, we take the value of the previous dp[i-1] or dp[j-1] accordingly if the characters match. For the base case, we start with initializing dp[0][0] to true since two empty strings can form an empty s3.

At the end of the iterations, the last element in the dp matrix (i.e. dp[m][n]) will represent whether s3 can be formed by an interleaving of s1 and s2.

## A solution in Python

```python
def isInterleave(s1, s2, s3):
    m, n = len(s1), len(s2)
    if m + n != len(s3):
        return False

    dp = [[False] * (n + 1) for _ in range(m + 1)]
    dp[0][0] = True
    for i in range(1, m + 1):
        dp[i][0] = dp[i - 1][0] and s1[i - 1] == s3[i - 1]
    for j in range(1, n + 1):
        dp[0][j] = dp[0][j - 1] and s2[j - 1] == s3[j - 1]

    for i in range(1, m + 1):
        for j in range(1, n + 1):
            dp[i][j] = (dp[i - 1][j] and s1[i - 1] == s3[i + j - 1]) or \
                       (dp[i][j - 1] and s2[j - 1] == s3[i + j - 1])

    return dp[m][n]
```
We use a dynamic programming approach (2D DP) to solve this problem. The algorithm checks whether the s3[position] is equal to s1 or s2 in the same dp[position]. If so, we take the value of the previous dp[i-1] or dp[j-1] accordingly if the characters match. For the base case, we start with initializing dp[0][0] to true since two empty strings can form an empty s3.

At the end of the iterations, the last element in the dp matrix (i.e. dp[m][n]) will represent whether s3 can be formed by an interleaving of s1 and s2.

## A solution in Javascript

```javascript
function isInterleave(s1, s2, s3) {
    let m = s1.length, n = s2.length;
    if (m + n !== s3.length) return false;

    let dp = new Array(m + 1).fill(null).map(() => new Array(n + 1).fill(false));
    dp[0][0] = true;
    for (let i = 1; i <= m; i++)
        dp[i][0] = dp[i - 1][0] && s1[i - 1] === s3[i - 1];
    for (let j = 1; j <= n; j++)
        dp[0][j] = dp[0][j - 1] && s2[j - 1] === s3[j - 1];

    for (let i = 1; i <= m; i++) {
        for (let j = 1; j <= n; j++) {
            dp[i][j] = (dp[i - 1][j] && s1[i - 1] === s3[i + j - 1]) ||
                       (dp[i][j - 1] && s2[j - 1] === s3[i + j - 1]);
        }
    }

    return dp[m][n];
}
```
We use a dynamic programming approach (2D DP) to solve this problem. The algorithm checks whether the s3[position] is equal to s1 or s2 in the same dp[position]. If so, we take the value of the previous dp[i-1] or dp[j-1] accordingly if the characters match. For the base case, we start with initializing dp[0][0] to true since two empty strings can form an empty s3.

At the end of the iterations, the last element in the dp matrix (i.e. dp[m][n]) will represent whether s3 can be formed by an interleaving of s1 and s2.