# Degree of an Array

- slug: degree-of-an-array
- difficulty: Easy

Given a non-empty array of non-negative integers `nums`, the **degree** of this array is defined as the maximum frequency of any one of its elements.

Your task is to find the smallest possible length of a (contiguous) subarray of `nums`, that has the same degree as `nums`.

**Example 1:**

**Input:** nums = \[1,2,2,3,1\]
**Output:** 2
**Explanation:**
The input array has a degree of 2 because both elements 1 and 2 appear twice.
Of the subarrays that have the same degree:
\[1, 2, 2, 3, 1\], \[1, 2, 2, 3\], \[2, 2, 3, 1\], \[1, 2, 2\], \[2, 2, 3\], \[2, 2\]
The shortest length is 2. So return 2.

**Example 2:**

**Input:** nums = \[1,2,2,3,1,4,2\]
**Output:** 6
**Explanation:**
The degree is 3 because the element 2 is repeated 3 times.
So \[2,2,3,1,4,2\] is the shortest subarray, therefore returning 6.

**Constraints:**

*   `nums.length` will be between 1 and 50,000.
*   `nums[i]` will be an integer between 0 and 49,999.

## A solution in Java

```java
import java.util.HashMap;

class Solution {
    public int findShortestSubArray(int[] nums) {
        HashMap<Integer, Integer> freq_map = new HashMap<>(), start_map = new HashMap<>();
        int max_freq = 0, min_length = nums.length;

        for (int i = 0; i < nums.length; ++i) {
            if (!start_map.containsKey(nums[i])) {
                start_map.put(nums[i], i);
            }
            freq_map.put(nums[i], freq_map.getOrDefault(nums[i], 0) + 1);

            int freq = freq_map.get(nums[i]);
            if (freq > max_freq) {
                max_freq = freq;
                min_length = i - start_map.get(nums[i]) + 1;
            } else if (freq == max_freq) {
                min_length = Math.min(min_length, i - start_map.get(nums[i]) + 1);
            }
        }

        return min_length;
    }
}
```
The algorithm first initializes two hash maps: `freq_map` to store the frequency count of each element and `start_map` to store the starting index of each unique element in the array. The max frequency `max_freq` and the minimum length `min_length` are initialized to 0 and the length of the input array, respectively.

Then, iterate through the input array, updating the frequency count of each element in `freq_map` and storing the starting index of each unique element in `start_map`.

For each index, update `max_freq` if a higher frequency is found. If the frequency is equal to `max_freq`, update `min_length` with the minimum length of the subarray having same degree as `nums`.

Finally, the algorithm returns the smallest length of a subarray with the maximum frequency. This approach has a time complexity of O(n), where n is the length of the input array.

## A solution in C++

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

int findShortestSubArray(std::vector<int>& nums) {
    std::unordered_map<int, int> freq_map, start_map;
    int max_freq = 0, min_length = nums.size();

    for (int i = 0; i < nums.size(); ++i) {
        if (start_map.count(nums[i]) == 0) {
            start_map[nums[i]] = i;
        }
        freq_map[nums[i]]++;

        int freq = freq_map[nums[i]];
        if (freq > max_freq) {
            max_freq = freq;
            min_length = i - start_map[nums[i]] + 1;
        } else if (freq == max_freq) {
            min_length = std::min(min_length, i - start_map[nums[i]] + 1);
        }
    }

    return min_length;
}
```
The algorithm first initializes two hash maps: `freq_map` to store the frequency count of each element and `start_map` to store the starting index of each unique element in the array. The max frequency `max_freq` and the minimum length `min_length` are initialized to 0 and the length of the input array, respectively.

Then, iterate through the input array, updating the frequency count of each element in `freq_map` and storing the starting index of each unique element in `start_map`.

For each index, update `max_freq` if a higher frequency is found. If the frequency is equal to `max_freq`, update `min_length` with the minimum length of the subarray having same degree as `nums`.

Finally, the algorithm returns the smallest length of a subarray with the maximum frequency. This approach has a time complexity of O(n), where n is the length of the input array.

## A solution in Python

```python
def findShortestSubArray(nums):
    freq_map, start_map = {}, {}
    max_freq, min_length = 0, len(nums)

    for i, num in enumerate(nums):
        if num not in start_map:
            start_map[num] = i
        freq_map[num] = freq_map.get(num, 0) + 1

        freq = freq_map[num]
        if freq > max_freq:
            max_freq = freq
            min_length = i - start_map[num] + 1
        elif freq == max_freq:
            min_length = min(min_length, i - start_map[num] + 1)

    return min_length
```
The algorithm first initializes two hash maps: `freq_map` to store the frequency count of each element and `start_map` to store the starting index of each unique element in the array. The max frequency `max_freq` and the minimum length `min_length` are initialized to 0 and the length of the input array, respectively.

Then, iterate through the input array, updating the frequency count of each element in `freq_map` and storing the starting index of each unique element in `start_map`.

For each index, update `max_freq` if a higher frequency is found. If the frequency is equal to `max_freq`, update `min_length` with the minimum length of the subarray having same degree as `nums`.

Finally, the algorithm returns the smallest length of a subarray with the maximum frequency. This approach has a time complexity of O(n), where n is the length of the input array.

## A solution in Javascript

```javascript
function findShortestSubArray(nums) {
    const freq_map = {}, start_map = {};
    let max_freq = 0, min_length = nums.length;

    for (let i = 0; i < nums.length; ++i) {
        if (!start_map.hasOwnProperty(nums[i])) {
            start_map[nums[i]] = i;
        }
        if (!freq_map.hasOwnProperty(nums[i])) {
            freq_map[nums[i]] = 0;
        }
        freq_map[nums[i]]++;

        const freq = freq_map[nums[i]];
        if (freq > max_freq) {
            max_freq = freq;
            min_length = i - start_map[nums[i]] + 1;
        } else if (freq === max_freq) {
            min_length = Math.min(min_length, i - start_map[nums[i]] + 1);
        }
    }

    return min_length;
}
```
The algorithm first initializes two hash maps: `freq_map` to store the frequency count of each element and `start_map` to store the starting index of each unique element in the array. The max frequency `max_freq` and the minimum length `min_length` are initialized to 0 and the length of the input array, respectively.

Then, iterate through the input array, updating the frequency count of each element in `freq_map` and storing the starting index of each unique element in `start_map`.

For each index, update `max_freq` if a higher frequency is found. If the frequency is equal to `max_freq`, update `min_length` with the minimum length of the subarray having same degree as `nums`.

Finally, the algorithm returns the smallest length of a subarray with the maximum frequency. This approach has a time complexity of O(n), where n is the length of the input array.


# Partition to K Equal Sum Subsets

- slug: partition-to-k-equal-sum-subsets
- difficulty: Medium

Given an integer array `nums` and an integer `k`, return `true` if it is possible to divide this array into `k` non-empty subsets whose sums are all equal.

**Example 1:**

**Input:** nums = \[4,3,2,3,5,2,1\], k = 4
**Output:** true
**Explanation:** It is possible to divide it into 4 subsets (5), (1, 4), (2,3), (2,3) with equal sums.

**Example 2:**

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

**Constraints:**

*   `1 <= k <= nums.length <= 16`
*   `1 <= nums[i] <= 104`
*   The frequency of each element is in the range `[1, 4]`.

## A solution in Java

```java
public boolean canPartitionKSubsets(int[] nums, int k) {
  int sum = 0;
  for (int num : nums) sum += num;
  if (sum % k != 0) return false;
  int target = sum / k;
  boolean[] visited = new boolean[nums.length];
  return dfs(nums, visited, 0, target, 0, k);
}

private boolean dfs(int[] nums, boolean[] visited, int start, int target, int curr_sum, int k) {
  if (k == 1) return true;
  if (curr_sum == target) return dfs(nums, visited, 0, target, 0, k - 1);
  for (int i = start; i < nums.length; i++) {
    if (!visited[i] && curr_sum + nums[i] <= target) {
      visited[i] = true;
      if (dfs(nums, visited, i + 1, target, curr_sum + nums[i], k)) return true;
      visited[i] = false;
    }
  }
  return false;
}
```
The algorithm uses depth-first search (DFS) to find possible subsets that sum up to the target value. The target is calculated by dividing the total sum of the array by k. The DFS function takes the following parameters: nums (the array), visited (a boolean array to keep track of visited elements), start (starting index for the current subset), target (target sum), curr_sum (current sum of the current subset), and k (number of subsets).

The base case is when k == 1, which means we have successfully found k - 1 subsets and the remaining elements automatically form the last subset, so we return true.

If curr_sum equals target, we found a valid subset, and we continue the search with k - 1 subsets starting from the beginning of the array.

The algorithm iterates through the array elements, checks if the element has not been visited, and if adding the element to the curr_sum doesn't exceed the target. If both conditions are met, the element is marked as visited, and the DFS is called recursively with the updated curr_sum and starting index. If the recursive call returns true, we found a valid set of subsets and return true. Otherwise, we backtrack by marking the element as unvisited.

If the DFS function doesn't find a solution, it returns false, indicating that it's not possible to divide the array into k equal subsets.

## A solution in C++

```cpp
#include <vector>
#include <numeric>

bool canPartitionKSubsets(std::vector<int>& nums, int k) {
  int sum = std::accumulate(nums.begin(), nums.end(), 0);
  if (sum % k != 0) return false;
  int target = sum / k;
  std::vector<bool> visited(nums.size(), false);
  return dfs(nums, visited, 0, target, 0, k);
}

bool dfs(std::vector<int>& nums, std::vector<bool>& visited, int start, int target, int curr_sum, int k) {
  if (k == 1) return true;
  if (curr_sum == target) return dfs(nums, visited, 0, target, 0, k - 1);
  for (int i = start; i < nums.size(); i++) {
    if (!visited[i] && curr_sum + nums[i] <= target) {
      visited[i] = true;
      if (dfs(nums, visited, i + 1, target, curr_sum + nums[i], k)) return true;
      visited[i] = false;
    }
  }
  return false;
}
```
The algorithm uses depth-first search (DFS) to find possible subsets that sum up to the target value. The target is calculated by dividing the total sum of the array by k. The DFS function takes the following parameters: nums (the array), visited (a boolean array to keep track of visited elements), start (starting index for the current subset), target (target sum), curr_sum (current sum of the current subset), and k (number of subsets).

The base case is when k == 1, which means we have successfully found k - 1 subsets and the remaining elements automatically form the last subset, so we return true.

If curr_sum equals target, we found a valid subset, and we continue the search with k - 1 subsets starting from the beginning of the array.

The algorithm iterates through the array elements, checks if the element has not been visited, and if adding the element to the curr_sum doesn't exceed the target. If both conditions are met, the element is marked as visited, and the DFS is called recursively with the updated curr_sum and starting index. If the recursive call returns true, we found a valid set of subsets and return true. Otherwise, we backtrack by marking the element as unvisited.

If the DFS function doesn't find a solution, it returns false, indicating that it's not possible to divide the array into k equal subsets.

## A solution in Python

```python
def canPartitionKSubsets(nums, k):
    total_sum = sum(nums)
    if total_sum % k != 0:
        return False
    target = total_sum // k
    visited = [False] * len(nums)
    return dfs(nums, visited, 0, target, 0, k)

def dfs(nums, visited, start, target, curr_sum, k):
    if k == 1:
        return True
    if curr_sum == target:
        return dfs(nums, visited, 0, target, 0, k - 1)
    for i in range(start, len(nums)):
        if not visited[i] and curr_sum + nums[i] <= target:
            visited[i] = True
            if dfs(nums, visited, i + 1, target, curr_sum + nums[i], k):
                return True
            visited[i] = False
    return False
```
The algorithm uses depth-first search (DFS) to find possible subsets that sum up to the target value. The target is calculated by dividing the total sum of the array by k. The DFS function takes the following parameters: nums (the array), visited (a boolean array to keep track of visited elements), start (starting index for the current subset), target (target sum), curr_sum (current sum of the current subset), and k (number of subsets).

The base case is when k == 1, which means we have successfully found k - 1 subsets and the remaining elements automatically form the last subset, so we return true.

If curr_sum equals target, we found a valid subset, and we continue the search with k - 1 subsets starting from the beginning of the array.

The algorithm iterates through the array elements, checks if the element has not been visited, and if adding the element to the curr_sum doesn't exceed the target. If both conditions are met, the element is marked as visited, and the DFS is called recursively with the updated curr_sum and starting index. If the recursive call returns true, we found a valid set of subsets and return true. Otherwise, we backtrack by marking the element as unvisited.

If the DFS function doesn't find a solution, it returns false, indicating that it's not possible to divide the array into k equal subsets.

## A solution in Javascript

```javascript
function canPartitionKSubsets(nums, k) {
  let sum = nums.reduce((a, b) => a + b, 0);
  if (sum % k !== 0) return false;
  const target = sum / k;
  const visited = new Array(nums.length).fill(false);
  return dfs(nums, visited, 0, target, 0, k);
}

function dfs(nums, visited, start, target, currSum, k) {
  if (k === 1) return true;
  if (currSum === target) return dfs(nums, visited, 0, target, 0, k - 1);
  for (let i = start; i < nums.length; i++) {
    if (!visited[i] && currSum + nums[i] <= target) {
      visited[i] = true;
      if (dfs(nums, visited, i + 1, target, currSum + nums[i], k)) return true;
      visited[i] = false;
    }
  }
  return false;
}
```
The algorithm uses depth-first search (DFS) to find possible subsets that sum up to the target value. The target is calculated by dividing the total sum of the array by k. The DFS function takes the following parameters: nums (the array), visited (a boolean array to keep track of visited elements), start (starting index for the current subset), target (target sum), curr_sum (current sum of the current subset), and k (number of subsets).

The base case is when k == 1, which means we have successfully found k - 1 subsets and the remaining elements automatically form the last subset, so we return true.

If curr_sum equals target, we found a valid subset, and we continue the search with k - 1 subsets starting from the beginning of the array.

The algorithm iterates through the array elements, checks if the element has not been visited, and if adding the element to the curr_sum doesn't exceed the target. If both conditions are met, the element is marked as visited, and the DFS is called recursively with the updated curr_sum and starting index. If the recursive call returns true, we found a valid set of subsets and return true. Otherwise, we backtrack by marking the element as unvisited.

If the DFS function doesn't find a solution, it returns false, indicating that it's not possible to divide the array into k equal subsets.


# Falling Squares

- slug: falling-squares
- difficulty: Hard

There are several squares being dropped onto the X-axis of a 2D plane.

You are given a 2D integer array `positions` where `positions[i] = [lefti, sideLengthi]` represents the `ith` square with a side length of `sideLengthi` that is dropped with its left edge aligned with X-coordinate `lefti`.

Each square is dropped one at a time from a height above any landed squares. It then falls downward (negative Y direction) until it either lands **on the top side of another square** or **on the X-axis**. A square brushing the left/right side of another square does not count as landing on it. Once it lands, it freezes in place and cannot be moved.

After each square is dropped, you must record the **height of the current tallest stack of squares**.

Return _an integer array_ `ans` _where_ `ans[i]` _represents the height described above after dropping the_ `ith` _square_.

**Example 1:**

**Input:** positions = \[\[1,2\],\[2,3\],\[6,1\]\]
**Output:** \[2,5,5\]
**Explanation:**
After the first drop, the tallest stack is square 1 with a height of 2.
After the second drop, the tallest stack is squares 1 and 2 with a height of 5.
After the third drop, the tallest stack is still squares 1 and 2 with a height of 5.
Thus, we return an answer of \[2, 5, 5\].

**Example 2:**

**Input:** positions = \[\[100,100\],\[200,100\]\]
**Output:** \[100,100\]
**Explanation:**
After the first drop, the tallest stack is square 1 with a height of 100.
After the second drop, the tallest stack is either square 1 or square 2, both with heights of 100.
Thus, we return an answer of \[100, 100\].
Note that square 2 only brushes the right side of square 1, which does not count as landing on it.

**Constraints:**

*   `1 <= positions.length <= 1000`
*   `1 <= lefti <= 108`
*   `1 <= sideLengthi <= 106`

## A solution in Java

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

public int[] fallingSquares(int[][] positions) {
    int[] ans = new int[positions.length];
    List<int[]> intervals = new ArrayList<>();

    for (int i = 0; i < positions.length; i++) {
        int L = positions[i][0];
        int R = positions[i][0] + positions[i][1];
        int h = positions[i][1];
        for (int[] interval : intervals) {
            if (interval[1] > L && R > interval[1]) {
                h = Math.max(h, positions[i][1] + interval[0]);
            }
        }

        int maxHeight = h;
        for (int[] interval : intervals) {
            maxHeight = Math.max(maxHeight, interval[0]);
        }

        ans[i] = maxHeight;
        intervals.add(new int[]{h, R});
    }

    return ans;
}
```
The function follows this algorithm:
1. Initialize an empty list `intervals` to store the height and right edge of each landed square, and an empty list `ans` to store the maximum height after each square has been dropped.
2. Loop through each square in `positions`.
3. For each square, find its left `L` and right `R` edge, and initialize its height `h` to its side length.
4. Loop through all intervals in `intervals`. Check if the current square intersects any existing square, and update the height `h` to its previous height plus the height of the intersected square.
5. Calculate the current maximum height by looping through all intervals and updating the maxHeight variable.
6. Append the new maxHeight to the answer array `ans`.
7. After dropping the current square, append its height and right edge to the `intervals` list.
8. Return the list `ans` as the final answer.

## A solution in C++

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

vector<int> fallingSquares(vector<vector<int>>& positions) {
    vector<int> ans;
    vector<pair<int, int>> intervals;

    for (auto p : positions) {
        int L = p[0];
        int R = p[0] + p[1];
        int h = p[1];
        for (auto it : intervals) {
            if (it.first < R && L < it.second) {
                h = max(h, p[1] + it.first);
            }
        }

        int maxHeight = h;
        for (auto it : intervals) {
            maxHeight = max(maxHeight, it.first);
        }

        ans.push_back(maxHeight);
        intervals.push_back(make_pair(h, R));
    }

    return ans;
}
```
The function follows this algorithm:
1. Initialize an empty list `intervals` to store the height and right edge of each landed square, and an empty list `ans` to store the maximum height after each square has been dropped.
2. Loop through each square in `positions`.
3. For each square, find its left `L` and right `R` edge, and initialize its height `h` to its side length.
4. Loop through all intervals in `intervals`. Check if the current square intersects any existing square, and update the height `h` to its previous height plus the height of the intersected square.
5. Calculate the current maximum height by looping through all intervals and updating the maxHeight variable.
6. Append the new maxHeight to the answer array `ans`.
7. After dropping the current square, append its height and right edge to the `intervals` list.
8. Return the list `ans` as the final answer.

## A solution in Python

```python
def fallingSquares(positions):
    ans = []
    intervals = []

    for p in positions:
        L, size = p
        R = L + size
        h = size
        for h2, R2 in intervals:
            if R2 > L and R > R2:
                h = max(h, size + h2)

        maxHeight = max((h2 for h2, R2 in intervals), default=0)
        ans.append(max(maxHeight, h))
        intervals.append((h, R))

    return ans
```
The function follows this algorithm:
1. Initialize an empty list `intervals` to store the height and right edge of each landed square, and an empty list `ans` to store the maximum height after each square has been dropped.
2. Loop through each square in `positions`.
3. For each square, find its left `L` and right `R` edge, and initialize its height `h` to its side length.
4. Loop through all intervals in `intervals`. Check if the current square intersects any existing square, and update the height `h` to its previous height plus the height of the intersected square.
5. Calculate the current maximum height by looping through all intervals and updating the maxHeight variable.
6. Append the new maxHeight to the answer array `ans`.
7. After dropping the current square, append its height and right edge to the `intervals` list.
8. Return the list `ans` as the final answer.

## A solution in Javascript

```javascript
function fallingSquares(positions) {
    let ans = [];
    let intervals = [];

    for (let p of positions) {
        let L = p[0];
        let R = p[0] + p[1];
        let h = p[1];
        for (let it of intervals) {
            if (it[1] > L && R > it[1]) {
                h = Math.max(h, p[1] + it[0]);
            }
        }

        let maxHeight = h;
        for (let it of intervals) {
            maxHeight = Math.max(maxHeight, it[0]);
        }

        ans.push(maxHeight);
        intervals.push([h, R]);
    }

    return ans;
}
```
The function follows this algorithm:
1. Initialize an empty list `intervals` to store the height and right edge of each landed square, and an empty list `ans` to store the maximum height after each square has been dropped.
2. Loop through each square in `positions`.
3. For each square, find its left `L` and right `R` edge, and initialize its height `h` to its side length.
4. Loop through all intervals in `intervals`. Check if the current square intersects any existing square, and update the height `h` to its previous height plus the height of the intersected square.
5. Calculate the current maximum height by looping through all intervals and updating the maxHeight variable.
6. Append the new maxHeight to the answer array `ans`.
7. After dropping the current square, append its height and right edge to the `intervals` list.
8. Return the list `ans` as the final answer.


# Search in a Binary Search Tree

- slug: search-in-a-binary-search-tree
- difficulty: Easy

You are given the `root` of a binary search tree (BST) and an integer `val`.

Find the node in the BST that the node's value equals `val` and return the subtree rooted with that node. If such a node does not exist, return `null`.

**Example 1:**

**Input:** root = \[4,2,7,1,3\], val = 2
**Output:** \[2,1,3\]

**Example 2:**

**Input:** root = \[4,2,7,1,3\], val = 5
**Output:** \[\]

**Constraints:**

*   The number of nodes in the tree is in the range `[1, 5000]`.
*   `1 <= Node.val <= 107`
*   `root` is a binary search tree.
*   `1 <= val <= 107`

## A solution in Java

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

public TreeNode searchBST(TreeNode root, int val) {
    if (root == null || root.val == val)
        return root;
    return (root.val < val) ? searchBST(root.right, val) : searchBST(root.left, val);
}
```
We use a recursive search function for searching the BST. The basic logic is as follows:
1. Check if the current node is `null` or its value equals the target value. If so, return the node itself.
2. If the target value is greater than the current node's value, search the right child.
3. If the target value is less than the current node's value, search the left child.

In all four programming languages, the implementation is pretty much the same:

1. Define a TreeNode structure/class with value, left child, and right child properties.
2. Apply the algorithm logic in the `searchBST` function.

## A solution in C++

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

TreeNode* searchBST(TreeNode* root, int val) {
    if (!root || root->val == val)
        return root;
    return (root->val < val) ? searchBST(root->right, val) : searchBST(root->left, val);
}
```
We use a recursive search function for searching the BST. The basic logic is as follows:
1. Check if the current node is `null` or its value equals the target value. If so, return the node itself.
2. If the target value is greater than the current node's value, search the right child.
3. If the target value is less than the current node's value, search the left child.

In all four programming languages, the implementation is pretty much the same:

1. Define a TreeNode structure/class with value, left child, and right child properties.
2. Apply the algorithm logic in the `searchBST` function.

## 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 searchBST(root: TreeNode, val: int) -> TreeNode:
    if not root or root.val == val:
        return root
    return searchBST(root.right, val) if root.val < val else searchBST(root.left, val)
```
We use a recursive search function for searching the BST. The basic logic is as follows:
1. Check if the current node is `null` or its value equals the target value. If so, return the node itself.
2. If the target value is greater than the current node's value, search the right child.
3. If the target value is less than the current node's value, search the left child.

In all four programming languages, the implementation is pretty much the same:

1. Define a TreeNode structure/class with value, left child, and right child properties.
2. Apply the algorithm logic in the `searchBST` function.

## A solution in Javascript

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

function searchBST(root, val) {
    if (!root || root.val === val) {
        return root;
    }
    return (root.val < val) ? searchBST(root.right, val) : searchBST(root.left, val);
}
```
We use a recursive search function for searching the BST. The basic logic is as follows:
1. Check if the current node is `null` or its value equals the target value. If so, return the node itself.
2. If the target value is greater than the current node's value, search the right child.
3. If the target value is less than the current node's value, search the left child.

In all four programming languages, the implementation is pretty much the same:

1. Define a TreeNode structure/class with value, left child, and right child properties.
2. Apply the algorithm logic in the `searchBST` function.


# Insert into a Binary Search Tree

- slug: insert-into-a-binary-search-tree
- difficulty: Medium

You are given the `root` node of a binary search tree (BST) and a `value` to insert into the tree. Return _the root node of the BST after the insertion_. It is **guaranteed** that the new value does not exist in the original BST.

**Notice** that there may exist multiple valid ways for the insertion, as long as the tree remains a BST after insertion. You can return **any of them**.

**Example 1:**

**Input:** root = \[4,2,7,1,3\], val = 5
**Output:** \[4,2,7,1,3,5\]
**Explanation:** Another accepted tree is:

**Example 2:**

**Input:** root = \[40,20,60,10,30,50,70\], val = 25
**Output:** \[40,20,60,10,30,50,70,null,null,25\]

**Example 3:**

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

**Constraints:**

*   The number of nodes in the tree will be in the range `[0, 104]`.
*   `-108 <= Node.val <= 108`
*   All the values `Node.val` are **unique**.
*   `-108 <= val <= 108`
*   It's **guaranteed** that `val` does not exist in the original BST.

## A solution in Java

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

    TreeNode() {}
    TreeNode(int val) { this.val = val; }
    TreeNode(int val, TreeNode left, TreeNode right) {
        this.val = val;
        this.left = left;
        this.right = right;
    }
}

public TreeNode insertIntoBST(TreeNode root, int val) {
    if (root == null) {
        return new TreeNode(val);
    }

    if (val < root.val) {
        root.left = insertIntoBST(root.left, val);
    } else {
        root.right = insertIntoBST(root.right, val);
    }

    return root;
}
```
The algorithm is a recursive algorithm that traverses the BST while looking for the correct position to insert the new value. From the root node, we compare the new value with the current node's value. If the new value is less than the current node's value, we move to the left child, and if the new value is greater, we move to the right child. We repeat this process until we reach a null child, in which case, we insert the new value as the child at that position. The base case is when the given root is null, in which case we simply return a new node with the value to insert. This guarantees that the resulting tree remains a valid BST after the insertion.

## A solution in C++

```cpp
class TreeNode {
public:
    int val;
    TreeNode *left;
    TreeNode *right;

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

TreeNode* insertIntoBST(TreeNode* root, int val) {
    if (!root) return new TreeNode(val);

    if (val < root->val) {
        root->left = insertIntoBST(root->left, val);
    } else {
        root->right = insertIntoBST(root->right, val);
    }

    return root;
}
```
The algorithm is a recursive algorithm that traverses the BST while looking for the correct position to insert the new value. From the root node, we compare the new value with the current node's value. If the new value is less than the current node's value, we move to the left child, and if the new value is greater, we move to the right child. We repeat this process until we reach a null child, in which case, we insert the new value as the child at that position. The base case is when the given root is null, in which case we simply return a new node with the value to insert. This guarantees that the resulting tree remains a valid BST after the insertion.

## 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 insertIntoBST(root, val):
    if root is None:
        return TreeNode(val)

    if val < root.val:
        root.left = insertIntoBST(root.left, val)
    else:
        root.right = insertIntoBST(root.right, val)

    return root
```
The algorithm is a recursive algorithm that traverses the BST while looking for the correct position to insert the new value. From the root node, we compare the new value with the current node's value. If the new value is less than the current node's value, we move to the left child, and if the new value is greater, we move to the right child. We repeat this process until we reach a null child, in which case, we insert the new value as the child at that position. The base case is when the given root is null, in which case we simply return a new node with the value to insert. This guarantees that the resulting tree remains a valid BST after the insertion.

## A solution in Javascript

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

function insertIntoBST(root, val) {
    if (!root) {
        return new TreeNode(val);
    }

    if (val < root.val) {
        root.left = insertIntoBST(root.left, val);
    } else {
        root.right = insertIntoBST(root.right, val);
    }

    return root;
}
```
The algorithm is a recursive algorithm that traverses the BST while looking for the correct position to insert the new value. From the root node, we compare the new value with the current node's value. If the new value is less than the current node's value, we move to the left child, and if the new value is greater, we move to the right child. We repeat this process until we reach a null child, in which case, we insert the new value as the child at that position. The base case is when the given root is null, in which case we simply return a new node with the value to insert. This guarantees that the resulting tree remains a valid BST after the insertion.


# Search in a Sorted Array of Unknown Size

- slug: search-in-a-sorted-array-of-unknown-size
- difficulty: Medium

This is an **_interactive problem_**.

You have a sorted array of **unique** elements and an **unknown size**. You do not have an access to the array but you can use the `ArrayReader` interface to access it. You can call `ArrayReader.get(i)` that:

*   returns the value at the `ith` index (**0-indexed**) of the secret array (i.e., `secret[i]`), or
*   returns `231 - 1` if the `i` is out of the boundary of the array.

You are also given an integer `target`.

Return the index `k` of the hidden array where `secret[k] == target` or return `-1` otherwise.

You must write an algorithm with `O(log n)` runtime complexity.

**Example 1:**

**Input:** secret = \[-1,0,3,5,9,12\], target = 9
**Output:** 4
**Explanation:** 9 exists in secret and its index is 4.

**Example 2:**

**Input:** secret = \[-1,0,3,5,9,12\], target = 2
**Output:** -1
**Explanation:** 2 does not exist in secret so return -1.

**Constraints:**

*   `1 <= secret.length <= 104`
*   `-104 <= secret[i], target <= 104`
*   `secret` is sorted in a strictly increasing order.

## A solution in Java

```java
public int search(ArrayReader reader, int target) {
    int left = 0, right = 1;
    while (reader.get(right) < target) {
        left = right;
        right <<= 1;
    }

    while (left <= right) {
        int mid = left + ((right - left) >> 1);
        int val = reader.get(mid);
        if (val == target)
            return mid;
        if (val > target)
            right = mid - 1;
        else
            left = mid + 1;
    }
    return -1;
}
```
We are using a binary search like algorithm to find the index. Initially, we set `left` to 0 and `right` to 1. Then we keep doubling the value of `right` (i.e., shifting it left by 1) until the value at `right` is greater than or equal to the target. This way, we can determine the range of the target value in the array, which is `[left, right]`.

Now we apply a binary search algorithm. We calculate the middle index and check the value at that index. If the value at the middle index is equal to the target, we return the middle index. If the value is greater than the target, we update `right` to `mid - 1`; if the value is smaller than the target, we update `left` to `mid + 1`. We do this until `left` becomes greater than `right`. If we cannot find the target value, we return -1.

The time complexity of this algorithm is O(log n) as we are reducing the search space by half each iteration.

## A solution in C++

```cpp
int search(const ArrayReader& reader, int target) {
    int left = 0, right = 1;
    while (reader.get(right) < target) {
        left = right;
        right <<= 1;
    }

    while (left <= right) {
        int mid = left + ((right - left) >> 1);
        int val = reader.get(mid);
        if (val == target)
            return mid;
        if (val > target)
            right = mid - 1;
        else
            left = mid + 1;
    }
    return -1;
}
```
We are using a binary search like algorithm to find the index. Initially, we set `left` to 0 and `right` to 1. Then we keep doubling the value of `right` (i.e., shifting it left by 1) until the value at `right` is greater than or equal to the target. This way, we can determine the range of the target value in the array, which is `[left, right]`.

Now we apply a binary search algorithm. We calculate the middle index and check the value at that index. If the value at the middle index is equal to the target, we return the middle index. If the value is greater than the target, we update `right` to `mid - 1`; if the value is smaller than the target, we update `left` to `mid + 1`. We do this until `left` becomes greater than `right`. If we cannot find the target value, we return -1.

The time complexity of this algorithm is O(log n) as we are reducing the search space by half each iteration.

## A solution in Python

```python
def search(reader, target):
    left, right = 0, 1
    while reader.get(right) < target:
        left = right
        right <<= 1

    while left <= right:
        mid = left + ((right - left) >> 1)
        val = reader.get(mid)
        if val == target:
            return mid
        if val > target:
            right = mid - 1
        else:
            left = mid + 1
    return -1
```
We are using a binary search like algorithm to find the index. Initially, we set `left` to 0 and `right` to 1. Then we keep doubling the value of `right` (i.e., shifting it left by 1) until the value at `right` is greater than or equal to the target. This way, we can determine the range of the target value in the array, which is `[left, right]`.

Now we apply a binary search algorithm. We calculate the middle index and check the value at that index. If the value at the middle index is equal to the target, we return the middle index. If the value is greater than the target, we update `right` to `mid - 1`; if the value is smaller than the target, we update `left` to `mid + 1`. We do this until `left` becomes greater than `right`. If we cannot find the target value, we return -1.

The time complexity of this algorithm is O(log n) as we are reducing the search space by half each iteration.

## A solution in Javascript

```javascript
function search(reader, target) {
    let left = 0, right = 1;
    while (reader.get(right) < target) {
        left = right;
        right <<= 1;
    }

    while (left <= right) {
        let mid = left + ((right - left) >> 1);
        let val = reader.get(mid);
        if (val === target)
            return mid;
        if (val > target)
            right = mid - 1;
        else
            left = mid + 1;
    }
    return -1;
}
```
We are using a binary search like algorithm to find the index. Initially, we set `left` to 0 and `right` to 1. Then we keep doubling the value of `right` (i.e., shifting it left by 1) until the value at `right` is greater than or equal to the target. This way, we can determine the range of the target value in the array, which is `[left, right]`.

Now we apply a binary search algorithm. We calculate the middle index and check the value at that index. If the value at the middle index is equal to the target, we return the middle index. If the value is greater than the target, we update `right` to `mid - 1`; if the value is smaller than the target, we update `left` to `mid + 1`. We do this until `left` becomes greater than `right`. If we cannot find the target value, we return -1.

The time complexity of this algorithm is O(log n) as we are reducing the search space by half each iteration.


# Kth Largest Element in a Stream

- slug: kth-largest-element-in-a-stream
- difficulty: Easy

Design a class to find the `kth` largest element in a stream. Note that it is the `kth` largest element in the sorted order, not the `kth` distinct element.

Implement `KthLargest` class:

*   `KthLargest(int k, int[] nums)` Initializes the object with the integer `k` and the stream of integers `nums`.
*   `int add(int val)` Appends the integer `val` to the stream and returns the element representing the `kth` largest element in the stream.

**Example 1:**

**Input**
\[ "KthLargest ",  "add ",  "add ",  "add ",  "add ",  "add "\]
\[\[3, \[4, 5, 8, 2\]\], \[3\], \[5\], \[10\], \[9\], \[4\]\]
**Output**
\[null, 4, 5, 5, 8, 8\]

**Explanation**
KthLargest kthLargest = new KthLargest(3, \[4, 5, 8, 2\]);
kthLargest.add(3);   // return 4
kthLargest.add(5);   // return 5
kthLargest.add(10);  // return 5
kthLargest.add(9);   // return 8
kthLargest.add(4);   // return 8

**Constraints:**

*   `1 <= k <= 104`
*   `0 <= nums.length <= 104`
*   `-104 <= nums[i] <= 104`
*   `-104 <= val <= 104`
*   At most `104` calls will be made to `add`.
*   It is guaranteed that there will be at least `k` elements in the array when you search for the `kth` element.

## A solution in Java

```java
import java.util.PriorityQueue;

class KthLargest {
    int k;
    PriorityQueue<Integer> minHeap;

    public KthLargest(int k, int[] nums) {
        this.k = k;
        minHeap = new PriorityQueue<>(k);
        for (int num : nums) {
            add(num);
        }
    }

    public int add(int val) {
        minHeap.offer(val);
        if (minHeap.size() > k) {
            minHeap.poll();
        }
        return minHeap.peek();
    }
}
```
We will use a min-heap to solve this problem. We initialize the KthLargest class with an integer `k` and an array `nums`. In the constructor, we loop through the `nums` array and call the `add` function for every element.

The `add` function does the following:
1. Pushes the new value into the min-heap.
2. If the size of the min-heap is greater than `k`, we pop an element from the min-heap (i.e., remove the smallest element).
3. We return the top element of the min-heap which represents the k-th largest element in the stream.

For the JavaScript implementation, we also need to create a separate MinHeap class covering the basic functions (offer, poll, peek, size) to maintain minimum priority queue.

All implementations follow the same algorithm, with small syntax differences between programming languages.

## A solution in C++

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

class KthLargest {
public:
    int k;
    std::priority_queue<int, std::vector<int>, std::greater<int>> minHeap;

    KthLargest(int k, std::vector<int>& nums) {
        this->k = k;
        for (int num : nums) {
            add(num);
        }
    }

    int add(int val) {
        minHeap.push(val);
        if (minHeap.size() > k) {
            minHeap.pop();
        }
        return minHeap.top();
    }
};
```
We will use a min-heap to solve this problem. We initialize the KthLargest class with an integer `k` and an array `nums`. In the constructor, we loop through the `nums` array and call the `add` function for every element.

The `add` function does the following:
1. Pushes the new value into the min-heap.
2. If the size of the min-heap is greater than `k`, we pop an element from the min-heap (i.e., remove the smallest element).
3. We return the top element of the min-heap which represents the k-th largest element in the stream.

For the JavaScript implementation, we also need to create a separate MinHeap class covering the basic functions (offer, poll, peek, size) to maintain minimum priority queue.

All implementations follow the same algorithm, with small syntax differences between programming languages.

## A solution in Python

```python
import heapq

class KthLargest:

    def __init__(self, k: int, nums: List[int]):
        self.k = k
        self.min_heap = nums
        heapq.heapify(self.min_heap)

        while len(self.min_heap) > k:
            heapq.heappop(self.min_heap)

    def add(self, val: int) -> int:
        if len(self.min_heap) < self.k:
            heapq.heappush(self.min_heap, val)
        elif val > self.min_heap[0]:
            heapq.heappushpop(self.min_heap, val)
        return self.min_heap[0]
```
We will use a min-heap to solve this problem. We initialize the KthLargest class with an integer `k` and an array `nums`. In the constructor, we loop through the `nums` array and call the `add` function for every element.

The `add` function does the following:
1. Pushes the new value into the min-heap.
2. If the size of the min-heap is greater than `k`, we pop an element from the min-heap (i.e., remove the smallest element).
3. We return the top element of the min-heap which represents the k-th largest element in the stream.

For the JavaScript implementation, we also need to create a separate MinHeap class covering the basic functions (offer, poll, peek, size) to maintain minimum priority queue.

All implementations follow the same algorithm, with small syntax differences between programming languages.

## A solution in Javascript

```javascript
class KthLargest {
    constructor(k, nums) {
        this.k = k;
        this.minHeap = new MinHeap();
        for (let num of nums) {
            this.add(num);
        }
    }

    add(val) {
        this.minHeap.offer(val);
        if (this.minHeap.size() > this.k) {
            this.minHeap.poll();
        }
        return this.minHeap.peek();
    }
}

class MinHeap {
    constructor() {
        this.heap = [];
    }

    offer(val) {
        this.heap.push(val);
        this.heap.sort((a, b) => a - b);
    }

    poll() {
        return this.heap.shift();
    }

    peek() {
        return this.heap[0];
    }

    size() {
        return this.heap.length;
    }
}
```
We will use a min-heap to solve this problem. We initialize the KthLargest class with an integer `k` and an array `nums`. In the constructor, we loop through the `nums` array and call the `add` function for every element.

The `add` function does the following:
1. Pushes the new value into the min-heap.
2. If the size of the min-heap is greater than `k`, we pop an element from the min-heap (i.e., remove the smallest element).
3. We return the top element of the min-heap which represents the k-th largest element in the stream.

For the JavaScript implementation, we also need to create a separate MinHeap class covering the basic functions (offer, poll, peek, size) to maintain minimum priority queue.

All implementations follow the same algorithm, with small syntax differences between programming languages.


# Binary Search

- slug: binary-search
- difficulty: Easy

Given an array of integers `nums` which is sorted in ascending order, and an integer `target`, write a function to search `target` in `nums`. If `target` exists, then return its index. Otherwise, return `-1`.

You must write an algorithm with `O(log n)` runtime complexity.

**Example 1:**

**Input:** nums = \[-1,0,3,5,9,12\], target = 9
**Output:** 4
**Explanation:** 9 exists in nums and its index is 4

**Example 2:**

**Input:** nums = \[-1,0,3,5,9,12\], target = 2
**Output:** -1
**Explanation:** 2 does not exist in nums so return -1

**Constraints:**

*   `1 <= nums.length <= 104`
*   `-104 < nums[i], target < 104`
*   All the integers in `nums` are **unique**.
*   `nums` is sorted in ascending order.

## A solution in Java

```java
public int search(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) return mid;
        if (nums[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}
```
The algorithm implements a binary search, since the input array is sorted in ascending order. We start with two pointers, `left` and `right`, representing the beginning and the end of the search range, respectively. We then find the middle element of the array (or subarray) by calculating the average of `left` and `right` and round it down.

If the middle element matches the target, we return its index. If the middle element is smaller than the target, we set `left` to the next index (`mid + 1`). If the middle element is greater than the target, we set `right` to the previous index (`mid - 1`). We continue iterating until we find the target or the pointers cross (`left > right`), in which case we return `-1` because the target is not in the array. The time complexity of this algorithm is O(log n).

## A solution in C++

```cpp
int search(vector<int>& nums, int target) {
    int left = 0, right = nums.size() - 1;
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] == target) return mid;
        if (nums[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}
```
The algorithm implements a binary search, since the input array is sorted in ascending order. We start with two pointers, `left` and `right`, representing the beginning and the end of the search range, respectively. We then find the middle element of the array (or subarray) by calculating the average of `left` and `right` and round it down.

If the middle element matches the target, we return its index. If the middle element is smaller than the target, we set `left` to the next index (`mid + 1`). If the middle element is greater than the target, we set `right` to the previous index (`mid - 1`). We continue iterating until we find the target or the pointers cross (`left > right`), in which case we return `-1` because the target is not in the array. The time complexity of this algorithm is O(log n).

## A solution in Python

```python
def search(nums: List[int], target: int) -> int:
    left, right = 0, len(nums) - 1
    while left <= right:
        mid = left + (right - left) // 2
        if nums[mid] == target:
            return mid
        if nums[mid] < target:
            left = mid + 1
        else:
            right = mid - 1
    return -1
```
The algorithm implements a binary search, since the input array is sorted in ascending order. We start with two pointers, `left` and `right`, representing the beginning and the end of the search range, respectively. We then find the middle element of the array (or subarray) by calculating the average of `left` and `right` and round it down.

If the middle element matches the target, we return its index. If the middle element is smaller than the target, we set `left` to the next index (`mid + 1`). If the middle element is greater than the target, we set `right` to the previous index (`mid - 1`). We continue iterating until we find the target or the pointers cross (`left > right`), in which case we return `-1` because the target is not in the array. The time complexity of this algorithm is O(log n).

## A solution in Javascript

```javascript
function search(nums, target) {
    let left = 0, right = nums.length - 1;
    while (left <= right) {
        const mid = Math.floor(left + (right - left) / 2);
        if (nums[mid] === target) return mid;
        if (nums[mid] < target) left = mid + 1;
        else right = mid - 1;
    }
    return -1;
}
```
The algorithm implements a binary search, since the input array is sorted in ascending order. We start with two pointers, `left` and `right`, representing the beginning and the end of the search range, respectively. We then find the middle element of the array (or subarray) by calculating the average of `left` and `right` and round it down.

If the middle element matches the target, we return its index. If the middle element is smaller than the target, we set `left` to the next index (`mid + 1`). If the middle element is greater than the target, we set `right` to the previous index (`mid - 1`). We continue iterating until we find the target or the pointers cross (`left > right`), in which case we return `-1` because the target is not in the array. The time complexity of this algorithm is O(log n).


# Design HashSet

- slug: design-hashset
- difficulty: Easy

Design a HashSet without using any built-in hash table libraries.

Implement `MyHashSet` class:

*   `void add(key)` Inserts the value `key` into the HashSet.
*   `bool contains(key)` Returns whether the value `key` exists in the HashSet or not.
*   `void remove(key)` Removes the value `key` in the HashSet. If `key` does not exist in the HashSet, do nothing.

**Example 1:**

**Input**
\[ "MyHashSet ",  "add ",  "add ",  "contains ",  "contains ",  "add ",  "contains ",  "remove ",  "contains "\]
\[\[\], \[1\], \[2\], \[1\], \[3\], \[2\], \[2\], \[2\], \[2\]\]
**Output**
\[null, null, null, true, false, null, true, null, false\]

**Explanation**
MyHashSet myHashSet = new MyHashSet();
myHashSet.add(1);      // set = \[1\]
myHashSet.add(2);      // set = \[1, 2\]
myHashSet.contains(1); // return True
myHashSet.contains(3); // return False, (not found)
myHashSet.add(2);      // set = \[1, 2\]
myHashSet.contains(2); // return True
myHashSet.remove(2);   // set = \[1\]
myHashSet.contains(2); // return False, (already removed)

**Constraints:**

*   `0 <= key <= 106`
*   At most `104` calls will be made to `add`, `remove`, and `contains`.

## A solution in Java

```java
class MyHashSet {
    boolean[] storage;

    public MyHashSet() {
        storage = new boolean[1000001];
    }

    public void add(int key) {
        storage[key] = true;
    }

    public void remove(int key) {
        storage[key] = false;
    }

    public boolean contains(int key) {
        return storage[key];
    }
}
```
The simplest way to implement a HashSet without using any built-in hash table libraries is to use an array of boolean values. The index of the array represents the key and the value at that index represents whether the key is present in the HashSet or not. In this case, we know the key range is `0 <= key <= 10^6`, so we can create an array with a length of `1000001`.

For the `add(key)` method, we set the value at the index of the key to be `true`.
For the `remove(key)` method, we set the value at the index of the key to be `false`.
For the `contains(key)` method, we check the value at the index of the key and return it.

The implementations of these methods are straightforward, and they are similar in each language. We create a storage array (vector in C++, boolean array in Java, list in Python, and array in JavaScript), and then we use simple array operations to manipulate the data.

## A solution in C++

```cpp
class MyHashSet {
public:
    vector<bool> storage;

    MyHashSet() : storage(1000001, false) { }

    void add(int key) {
        storage[key] = true;
    }

    void remove(int key) {
        storage[key] = false;
    }

    bool contains(int key) {
        return storage[key];
    }
};
```
The simplest way to implement a HashSet without using any built-in hash table libraries is to use an array of boolean values. The index of the array represents the key and the value at that index represents whether the key is present in the HashSet or not. In this case, we know the key range is `0 <= key <= 10^6`, so we can create an array with a length of `1000001`.

For the `add(key)` method, we set the value at the index of the key to be `true`.
For the `remove(key)` method, we set the value at the index of the key to be `false`.
For the `contains(key)` method, we check the value at the index of the key and return it.

The implementations of these methods are straightforward, and they are similar in each language. We create a storage array (vector in C++, boolean array in Java, list in Python, and array in JavaScript), and then we use simple array operations to manipulate the data.

## A solution in Python

```python
class MyHashSet:

    def __init__(self):
        self.storage = [False] * 1000001

    def add(self, key: int):
        self.storage[key] = True

    def remove(self, key: int):
        self.storage[key] = False

    def contains(self, key: int) -> bool:
        return self.storage[key]
```
The simplest way to implement a HashSet without using any built-in hash table libraries is to use an array of boolean values. The index of the array represents the key and the value at that index represents whether the key is present in the HashSet or not. In this case, we know the key range is `0 <= key <= 10^6`, so we can create an array with a length of `1000001`.

For the `add(key)` method, we set the value at the index of the key to be `true`.
For the `remove(key)` method, we set the value at the index of the key to be `false`.
For the `contains(key)` method, we check the value at the index of the key and return it.

The implementations of these methods are straightforward, and they are similar in each language. We create a storage array (vector in C++, boolean array in Java, list in Python, and array in JavaScript), and then we use simple array operations to manipulate the data.

## A solution in Javascript

```javascript
class MyHashSet {
    constructor() {
        this.storage = new Array(1000001).fill(false);
    }

    add(key) {
        this.storage[key] = true;
    }

    remove(key) {
        this.storage[key] = false;
    }

    contains(key) {
        return this.storage[key];
    }
}
```
The simplest way to implement a HashSet without using any built-in hash table libraries is to use an array of boolean values. The index of the array represents the key and the value at that index represents whether the key is present in the HashSet or not. In this case, we know the key range is `0 <= key <= 10^6`, so we can create an array with a length of `1000001`.

For the `add(key)` method, we set the value at the index of the key to be `true`.
For the `remove(key)` method, we set the value at the index of the key to be `false`.
For the `contains(key)` method, we check the value at the index of the key and return it.

The implementations of these methods are straightforward, and they are similar in each language. We create a storage array (vector in C++, boolean array in Java, list in Python, and array in JavaScript), and then we use simple array operations to manipulate the data.


# Design HashMap

- slug: design-hashmap
- difficulty: Easy

Design a HashMap without using any built-in hash table libraries.

Implement the `MyHashMap` class:

*   `MyHashMap()` initializes the object with an empty map.
*   `void put(int key, int value)` inserts a `(key, value)` pair into the HashMap. If the `key` already exists in the map, update the corresponding `value`.
*   `int get(int key)` returns the `value` to which the specified `key` is mapped, or `-1` if this map contains no mapping for the `key`.
*   `void remove(key)` removes the `key` and its corresponding `value` if the map contains the mapping for the `key`.

**Example 1:**

**Input**
\[ "MyHashMap ",  "put ",  "put ",  "get ",  "get ",  "put ",  "get ",  "remove ",  "get "\]
\[\[\], \[1, 1\], \[2, 2\], \[1\], \[3\], \[2, 1\], \[2\], \[2\], \[2\]\]
**Output**
\[null, null, null, 1, -1, null, 1, null, -1\]

**Explanation**
MyHashMap myHashMap = new MyHashMap();
myHashMap.put(1, 1); // The map is now \[\[1,1\]\]
myHashMap.put(2, 2); // The map is now \[\[1,1\], \[2,2\]\]
myHashMap.get(1);    // return 1, The map is now \[\[1,1\], \[2,2\]\]
myHashMap.get(3);    // return -1 (i.e., not found), The map is now \[\[1,1\], \[2,2\]\]
myHashMap.put(2, 1); // The map is now \[\[1,1\], \[2,1\]\] (i.e., update the existing value)
myHashMap.get(2);    // return 1, The map is now \[\[1,1\], \[2,1\]\]
myHashMap.remove(2); // remove the mapping for 2, The map is now \[\[1,1\]\]
myHashMap.get(2);    // return -1 (i.e., not found), The map is now \[\[1,1\]\]

**Constraints:**

*   `0 <= key, value <= 106`
*   At most `104` calls will be made to `put`, `get`, and `remove`.

## A solution in Java

```java
import java.util.LinkedList;

class MyHashMap {
    private LinkedList<Pair>[] data;
    private static final int size = 10007;

    public MyHashMap() {
        data = new LinkedList[size];
        for (int i = 0; i < size; ++i) {
            data[i] = new LinkedList<>();
        }
    }

    public void put(int key, int value) {
        LinkedList<Pair> bucket = data[key % size];
        for (Pair pair : bucket) {
            if (pair.getKey() == key) {
                pair.setValue(value);
                return;
            }
        }
        bucket.add(new Pair(key, value));
    }

    public int get(int key) {
        LinkedList<Pair> bucket = data[key % size];
        for (Pair pair : bucket) {
            if (pair.getKey() == key) {
                return pair.getValue();
            }
        }
        return -1;
    }

    public void remove(int key) {
        LinkedList<Pair> bucket = data[key % size];
        bucket.removeIf(pair -> pair.getKey() == key);
    }

    private static class Pair {
        int key;
        int value;

        Pair(int key, int value) {
            this.key = key;
            this.value = value;
        }

        int getKey() {
            return key;
        }

        int getValue() {
            return value;
        }

        void setValue(int value) {
            this.value = value;
        }
    }
}
```
The basic strategy for a simple hash map, given that the number of keys will be at most 10^4, is to use a hashing function to map an integer key to an index in an array or list of "buckets". We will use the modulo operation to do this, with a prime number for the size (e.g., 10007) to minimize the likelihood of collisions.

Each "bucket" is a list that can store the (key, value) pairs with the same hash. When a collision happens (i.e., two keys share the same hash), we simply append the new value to the list of that same "bucket". We use separate chaining in the linked list, which means that if two values collide, they will coexist in the same bucket.

To perform the `put` operation, we first hash the key modulo the size to find the corresponding bucket. We iterate through this bucket to check if the key already exists; if so, we update its value, and otherwise, we insert a new (key, value) pair at the end of the list.

The `get` operation works similarly to `put`: we find the corresponding bucket by hashing the key modulo the size, then iterate through the list to find the requested key. If we find the key, we return the associated value; otherwise, we return -1 to indicate that the key is not in the hash map.

For the `remove` operation, we again find the corresponding bucket, then iterate through the list to find the pair with the matching key, and remove it from the list if found.

The complexity of this solution is O(N/K) for each operation (where N is the number of all possible keys and K is the size of the array), but if the number of keys is much smaller than the size of the array, the operations are sufficiently quick.

## A solution in C++

```cpp
class MyHashMap {
public:
    vector<list<pair<int, int>>> data;
    static const int size = 10007;

    MyHashMap() {
        data = vector<list<pair<int, int>>>(size);
    }

    void put(int key, int value) {
        auto& bucket = data[key % size];
        for (auto& pair : bucket) {
            if (pair.first == key) {
                pair.second = value;
                return;
            }
        }
        bucket.emplace_back(key, value);
    }

    int get(int key) {
        const auto& bucket = data[key % size];
        for (const auto& pair : bucket) {
            if (pair.first == key) {
                return pair.second;
            }
        }
        return -1;
    }

    void remove(int key) {
        auto& bucket = data[key % size];
        bucket.remove_if([key](const auto& pair) { return pair.first == key; });
    }
};
```
The basic strategy for a simple hash map, given that the number of keys will be at most 10^4, is to use a hashing function to map an integer key to an index in an array or list of "buckets". We will use the modulo operation to do this, with a prime number for the size (e.g., 10007) to minimize the likelihood of collisions.

Each "bucket" is a list that can store the (key, value) pairs with the same hash. When a collision happens (i.e., two keys share the same hash), we simply append the new value to the list of that same "bucket". We use separate chaining in the linked list, which means that if two values collide, they will coexist in the same bucket.

To perform the `put` operation, we first hash the key modulo the size to find the corresponding bucket. We iterate through this bucket to check if the key already exists; if so, we update its value, and otherwise, we insert a new (key, value) pair at the end of the list.

The `get` operation works similarly to `put`: we find the corresponding bucket by hashing the key modulo the size, then iterate through the list to find the requested key. If we find the key, we return the associated value; otherwise, we return -1 to indicate that the key is not in the hash map.

For the `remove` operation, we again find the corresponding bucket, then iterate through the list to find the pair with the matching key, and remove it from the list if found.

The complexity of this solution is O(N/K) for each operation (where N is the number of all possible keys and K is the size of the array), but if the number of keys is much smaller than the size of the array, the operations are sufficiently quick.

## A solution in Python

```python
class MyHashMap:
    def __init__(self):
        self.size = 10007
        self.data = [[] for _ in range(self.size)]

    def put(self, key: int, value: int) -> None:
        bucket = self.data[key % self.size]
        for pair in bucket:
            if pair[0] == key:
                pair[1] = value
                return
        bucket.append([key, value])

    def get(self, key: int) -> int:
        bucket = self.data[key % self.size]
        for pair in bucket:
            if pair[0] == key:
                return pair[1]
        return -1

    def remove(self, key: int) -> None:
        bucket = self.data[key % self.size]
        for i, pair in enumerate(bucket):
            if pair[0] == key:
                bucket.pop(i)
                return
```
The basic strategy for a simple hash map, given that the number of keys will be at most 10^4, is to use a hashing function to map an integer key to an index in an array or list of "buckets". We will use the modulo operation to do this, with a prime number for the size (e.g., 10007) to minimize the likelihood of collisions.

Each "bucket" is a list that can store the (key, value) pairs with the same hash. When a collision happens (i.e., two keys share the same hash), we simply append the new value to the list of that same "bucket". We use separate chaining in the linked list, which means that if two values collide, they will coexist in the same bucket.

To perform the `put` operation, we first hash the key modulo the size to find the corresponding bucket. We iterate through this bucket to check if the key already exists; if so, we update its value, and otherwise, we insert a new (key, value) pair at the end of the list.

The `get` operation works similarly to `put`: we find the corresponding bucket by hashing the key modulo the size, then iterate through the list to find the requested key. If we find the key, we return the associated value; otherwise, we return -1 to indicate that the key is not in the hash map.

For the `remove` operation, we again find the corresponding bucket, then iterate through the list to find the pair with the matching key, and remove it from the list if found.

The complexity of this solution is O(N/K) for each operation (where N is the number of all possible keys and K is the size of the array), but if the number of keys is much smaller than the size of the array, the operations are sufficiently quick.

## A solution in Javascript

```javascript
class MyHashMap {
    constructor() {
        this.size = 10007;
        this.data = new Array(this.size).fill(null).map(() => []);
    }

    put(key, value) {
        const bucket = this.data[key % this.size];
        for (const pair of bucket) {
            if (pair[0] === key) {
                pair[1] = value;
                return;
            }
        }
        bucket.push([key, value]);
    }

    get(key) {
        const bucket = this.data[key % this.size];
        for (const pair of bucket) {
            if (pair[0] === key) {
                return pair[1];
            }
        }
        return -1;
    }

    remove(key) {
        const bucket = this.data[key % this.size];
        const index = bucket.findIndex(pair => pair[0] === key);
        if (index !== -1) {
            bucket.splice(index, 1);
        }
    }
}
```
The basic strategy for a simple hash map, given that the number of keys will be at most 10^4, is to use a hashing function to map an integer key to an index in an array or list of "buckets". We will use the modulo operation to do this, with a prime number for the size (e.g., 10007) to minimize the likelihood of collisions.

Each "bucket" is a list that can store the (key, value) pairs with the same hash. When a collision happens (i.e., two keys share the same hash), we simply append the new value to the list of that same "bucket". We use separate chaining in the linked list, which means that if two values collide, they will coexist in the same bucket.

To perform the `put` operation, we first hash the key modulo the size to find the corresponding bucket. We iterate through this bucket to check if the key already exists; if so, we update its value, and otherwise, we insert a new (key, value) pair at the end of the list.

The `get` operation works similarly to `put`: we find the corresponding bucket by hashing the key modulo the size, then iterate through the list to find the requested key. If we find the key, we return the associated value; otherwise, we return -1 to indicate that the key is not in the hash map.

For the `remove` operation, we again find the corresponding bucket, then iterate through the list to find the pair with the matching key, and remove it from the list if found.

The complexity of this solution is O(N/K) for each operation (where N is the number of all possible keys and K is the size of the array), but if the number of keys is much smaller than the size of the array, the operations are sufficiently quick.


# Design Linked List

- slug: design-linked-list
- difficulty: Medium

Design your implementation of the linked list. You can choose to use a singly or doubly linked list.
A node in a singly linked list should have two attributes: `val` and `next`. `val` is the value of the current node, and `next` is a pointer/reference to the next node.
If you want to use the doubly linked list, you will need one more attribute `prev` to indicate the previous node in the linked list. Assume all nodes in the linked list are **0-indexed**.

Implement the `MyLinkedList` class:

*   `MyLinkedList()` Initializes the `MyLinkedList` object.
*   `int get(int index)` Get the value of the `indexth` node in the linked list. If the index is invalid, return `-1`.
*   `void addAtHead(int val)` Add a node of value `val` before the first element of the linked list. After the insertion, the new node will be the first node of the linked list.
*   `void addAtTail(int val)` Append a node of value `val` as the last element of the linked list.
*   `void addAtIndex(int index, int val)` Add a node of value `val` before the `indexth` node in the linked list. If `index` equals the length of the linked list, the node will be appended to the end of the linked list. If `index` is greater than the length, the node **will not be inserted**.
*   `void deleteAtIndex(int index)` Delete the `indexth` node in the linked list, if the index is valid.

**Example 1:**

**Input**
\[ "MyLinkedList ",  "addAtHead ",  "addAtTail ",  "addAtIndex ",  "get ",  "deleteAtIndex ",  "get "\]
\[\[\], \[1\], \[3\], \[1, 2\], \[1\], \[1\], \[1\]\]
**Output**
\[null, null, null, null, 2, null, 3\]

**Explanation**
MyLinkedList myLinkedList = new MyLinkedList();
myLinkedList.addAtHead(1);
myLinkedList.addAtTail(3);
myLinkedList.addAtIndex(1, 2);    // linked list becomes 1->2->3
myLinkedList.get(1);              // return 2
myLinkedList.deleteAtIndex(1);    // now the linked list is 1->3
myLinkedList.get(1);              // return 3

**Constraints:**

*   `0 <= index, val <= 1000`
*   Please do not use the built-in LinkedList library.
*   At most `2000` calls will be made to `get`, `addAtHead`, `addAtTail`, `addAtIndex` and `deleteAtIndex`.

## A solution in Java

```java
class Node {
    int val;
    Node next;
    Node(int val) {
        this.val = val;
        this.next = null;
    }
}

class MyLinkedList {
    Node head;
    int size;

    public MyLinkedList() {
        head = null;
        size = 0;
    }

    public int get(int index) {
        if (index < 0 || index >= size) return -1;
        Node cur = head;
        for (int i = 0; i < index; i++) {
            cur = cur.next;
        }
        return cur.val;
    }

    public void addAtHead(int val) {
        Node newNode = new Node(val);
        newNode.next = head;
        head = newNode;
        size++;
    }

    public void addAtTail(int val) {
        if (size == 0) {
            addAtHead(val);
        } else {
            Node cur = head;
            while (cur.next != null) {
                cur = cur.next;
            }
            cur.next = new Node(val);
            size++;
        }
    }

    public void addAtIndex(int index, int val) {
        if (index < 0 || index > size) return;
        if (index == 0) {
            addAtHead(val);
        } else {
            Node cur = head;
            for (int i = 0; i < index - 1; i++) {
                cur = cur.next;
            }
            Node newNode = new Node(val);
            newNode.next = cur.next;
            cur.next = newNode;
            size++;
        }
    }

    public void deleteAtIndex(int index) {
        if (index < 0 || index >= size) return;
        if (index == 0) {
            Node tmp = head;
            head = head.next;
            tmp.next = null; // help GC
        } else {
            Node cur = head;
            for (int i = 0; i < index - 1; i++) {
                cur = cur.next;
            }
            Node tmp = cur.next;
            cur.next = tmp.next;
            tmp.next = null; // help GC
        }
        size--;
    }
}
```
1. Create a Node class with val and next as attributes.
2. Implement MyLinkedList class with the following member functions:
    - get(index): Iterate through the list until reaching the specified index and return its value. Return -1 if the index is out of range.
    - addAtHead(val): Add a new node with a given value to the head of the list.
    - addAtTail(val): Add a new node with a given value to the tail of the list.
    - addAtIndex(index, val): Find the node before the specified index and insert a new node with a given value after it.
    - deleteAtIndex(index): Find the node before the specified index and remove the node at that index.
3. Maintain a size attribute to keep track of the list size.

## A solution in C++

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

class MyLinkedList {
public:
    MyLinkedList() : head(nullptr), size(0) {}

    int get(int index) {
        if (index < 0 || index >= size) return -1;
        Node* cur = head;
        for (int i = 0; i < index; ++i) {
            cur = cur->next;
        }
        return cur->val;
    }

    void addAtHead(int val) {
        Node* newNode = new Node(val);
        newNode->next = head;
        head = newNode;
        size++;
    }

    void addAtTail(int val) {
        if (size == 0) {
            addAtHead(val);
        } else {
            Node* cur = head;
            while (cur->next) {
                cur = cur->next;
            }
            cur->next = new Node(val);
            size++;
        }
    }

    void addAtIndex(int index, int val) {
        if (index < 0 || index > size) return;
        if (index == 0) {
            addAtHead(val);
        } else {
            Node* cur = head;
            for (int i = 0; i < index - 1; ++i) {
                cur = cur->next;
            }
            Node* newNode = new Node(val);
            newNode->next = cur->next;
            cur->next = newNode;
            size++;
        }
    }

    void deleteAtIndex(int index) {
        if (index < 0 || index >= size) return;
        if (index == 0) {
            Node* tmp = head;
            head = head->next;
            delete tmp;
        } else {
            Node* cur = head;
            for (int i = 0; i < index - 1; ++i) {
                cur = cur->next;
            }
            Node* tmp = cur->next;
            cur->next = tmp->next;
            delete tmp;
        }
        size--;
    }

private:
    Node* head;
    int size;
};
```
1. Create a Node class with val and next as attributes.
2. Implement MyLinkedList class with the following member functions:
    - get(index): Iterate through the list until reaching the specified index and return its value. Return -1 if the index is out of range.
    - addAtHead(val): Add a new node with a given value to the head of the list.
    - addAtTail(val): Add a new node with a given value to the tail of the list.
    - addAtIndex(index, val): Find the node before the specified index and insert a new node with a given value after it.
    - deleteAtIndex(index): Find the node before the specified index and remove the node at that index.
3. Maintain a size attribute to keep track of the list size.

## A solution in Python

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

class MyLinkedList:
    def __init__(self):
        self.head = None
        self.size = 0

    def get(self, index: int) -> int:
        if index < 0 or index >= self.size:
            return -1
        cur = self.head
        for _ in range(index):
            cur = cur.next
        return cur.val

    def addAtHead(self, val: int) -> None:
        self.head = Node(val, self.head)
        self.size += 1

    def addAtTail(self, val: int) -> None:
        if self.size == 0:
            self.addAtHead(val)
        else:
            cur = self.head
            while cur.next:
                cur = cur.next
            cur.next = Node(val)
            self.size += 1

    def addAtIndex(self, index: int, val: int) -> None:
        if index < 0 or index > self.size:
            return
        if index == 0:
            self.addAtHead(val)
        else:
            cur = self.head
            for _ in range(index - 1):
                cur = cur.next
            cur.next = Node(val, cur.next)
            self.size += 1

    def deleteAtIndex(self, index: int) -> None:
        if index < 0 or index >= self.size:
            return
        if index == 0:
            self.head = self.head.next
        else:
            cur = self.head
            for _ in range(index - 1):
                cur = cur.next
            cur.next = cur.next.next
        self.size -= 1
```
1. Create a Node class with val and next as attributes.
2. Implement MyLinkedList class with the following member functions:
    - get(index): Iterate through the list until reaching the specified index and return its value. Return -1 if the index is out of range.
    - addAtHead(val): Add a new node with a given value to the head of the list.
    - addAtTail(val): Add a new node with a given value to the tail of the list.
    - addAtIndex(index, val): Find the node before the specified index and insert a new node with a given value after it.
    - deleteAtIndex(index): Find the node before the specified index and remove the node at that index.
3. Maintain a size attribute to keep track of the list size.

## A solution in Javascript

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

class MyLinkedList {
  constructor() {
    this.head = null;
    this.size = 0;
  }

  get(index) {
    if (index < 0 || index >= this.size) return -1;
    let cur = this.head;
    for (let i = 0; i < index; i++) {
      cur = cur.next;
    }
    return cur.val;
  }

  addAtHead(val) {
    this.head = new Node(val, this.head);
    this.size++;
  }

  addAtTail(val) {
    if (this.size === 0) {
      this.addAtHead(val);
    } else {
      let cur = this.head;
      while (cur.next) {
        cur = cur.next;
      }
      cur.next = new Node(val);
      this.size++;
    }
  }

  addAtIndex(index, val) {
    if (index < 0 || index > this.size) return;
    if (index === 0) {
      this.addAtHead(val);
    } else {
      let cur = this.head;
      for (let i = 0; i < index - 1; i++) {
        cur = cur.next;
      }
      cur.next = new Node(val, cur.next);
      this.size++;
    }
  }

  deleteAtIndex(index) {
    if (index < 0 || index >= this.size) return;
    if (index === 0) {
      this.head = this.head.next;
    } else {
      let cur = this.head;
      for (let i = 0; i < index - 1; i++) {
        cur = cur.next;
      }
      cur.next = cur.next.next;
    }
    this.size--;
  }
}
```
1. Create a Node class with val and next as attributes.
2. Implement MyLinkedList class with the following member functions:
    - get(index): Iterate through the list until reaching the specified index and return its value. Return -1 if the index is out of range.
    - addAtHead(val): Add a new node with a given value to the head of the list.
    - addAtTail(val): Add a new node with a given value to the tail of the list.
    - addAtIndex(index, val): Find the node before the specified index and insert a new node with a given value after it.
    - deleteAtIndex(index): Find the node before the specified index and remove the node at that index.
3. Maintain a size attribute to keep track of the list size.


# Insert into a Sorted Circular Linked List

- slug: insert-into-a-sorted-circular-linked-list
- difficulty: Medium

Given a Circular Linked List node, which is sorted in non-descending order, write a function to insert a value `insertVal` into the list such that it remains a sorted circular list. The given node can be a reference to any single node in the list and may not necessarily be the smallest value in the circular list.

If there are multiple suitable places for insertion, you may choose any place to insert the new value. After the insertion, the circular list should remain sorted.

If the list is empty (i.e., the given node is `null`), you should create a new single circular list and return the reference to that single node. Otherwise, you should return the originally given node.

**Example 1:**

**Input:** head = \[3,4,1\], insertVal = 2
**Output:** \[3,4,1,2\]
**Explanation:** In the figure above, there is a sorted circular list of three elements. You are given a reference to the node with value 3, and we need to insert 2 into the list. The new node should be inserted between node 1 and node 3. After the insertion, the list should look like this, and we should still return node 3.

**Example 2:**

**Input:** head = \[\], insertVal = 1
**Output:** \[1\]
**Explanation:** The list is empty (given head is `null`). We create a new single circular list and return the reference to that single node.

**Example 3:**

**Input:** head = \[1\], insertVal = 0
**Output:** \[1,0\]

**Constraints:**

*   The number of nodes in the list is in the range `[0, 5 * 104]`.
*   `-106 <= Node.val, insertVal <= 106`

## A solution in Java

```java
class Node {
    int val;
    Node next;
    Node() { val = 0; next = null; }
    Node(int _val) { val = _val; next = null; }
    Node(int _val, Node _next) { val = _val; next = _next; }
}

public Node insert(Node head, int insertVal) {
    if (head == null) {
        Node newNode = new Node(insertVal, null);
        newNode.next = newNode;
        return newNode;
    }

    Node prev = head;
    Node curr = head.next;
    boolean inserted = false;

    do {
        if (prev.val <= insertVal && insertVal <= curr.val) {
            prev.next = new Node(insertVal, curr);
            inserted = true;
        } else if (prev.val > curr.val) {
            if (insertVal >= prev.val || insertVal <= curr.val) {
                prev.next = new Node(insertVal, curr);
                inserted = true;
            }
        }
        prev = curr;
        curr = curr.next;
    } while (prev != head && !inserted);

    if (!inserted) {
        prev.next = new Node(insertVal, curr);
    }

    return head;
}
```
1. If the given `head` is `null`, we create a new node with the value `insertVal`, make it circular by pointing its `next` to itself, and return it.

2. If `head` is not `null`, we start iterating the list from head to the next node.

3. If `insertVal` fits between the values of the previous and current nodes considering the sorted list, add a new node with the value `insertVal` between previous and current nodes.

4. If the value of the previous node is greater than the value of the current node (it means we reached the end of the list and looped back to the start) AND `insertVal` fits in that range, add a new node with the value `insertVal` between those nodes.

5. If we complete the iteration without inserting the node, insert a new node with the value `insertVal` between the last previous node and its next.

6. Return the original given `head`.

## A solution in C++

```cpp
class Node {
public:
    int val;
    Node* next;
    Node() : val(0), next(nullptr) {}
    Node(int _val) : val(_val), next(nullptr) {}
    Node(int _val, Node* _next) : val(_val), next(_next) {}
};

Node* insert(Node* head, int insertVal) {
    if (head == nullptr) {
        Node* newNode = new Node(insertVal);
        newNode->next = newNode;
        return newNode;
    }

    Node* prev = head;
    Node* curr = head->next;
    bool inserted = false;

    do {
        if (prev->val <= insertVal && insertVal <= curr->val) {
            prev->next = new Node(insertVal, curr);
            inserted = true;
        } else if (prev->val > curr->val) {
            if (insertVal >= prev->val || insertVal <= curr->val) {
                prev->next = new Node(insertVal, curr);
                inserted = true;
            }
        }
        prev = curr;
        curr = curr->next;
    } while (prev != head && !inserted);

    if (!inserted) {
        prev->next = new Node(insertVal, curr);
    }

    return head;
}
```
1. If the given `head` is `null`, we create a new node with the value `insertVal`, make it circular by pointing its `next` to itself, and return it.

2. If `head` is not `null`, we start iterating the list from head to the next node.

3. If `insertVal` fits between the values of the previous and current nodes considering the sorted list, add a new node with the value `insertVal` between previous and current nodes.

4. If the value of the previous node is greater than the value of the current node (it means we reached the end of the list and looped back to the start) AND `insertVal` fits in that range, add a new node with the value `insertVal` between those nodes.

5. If we complete the iteration without inserting the node, insert a new node with the value `insertVal` between the last previous node and its next.

6. Return the original given `head`.

## A solution in Python

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

def insert(head, insertVal):
    if head is None:
        newNode = Node(insertVal)
        newNode.next = newNode
        return newNode

    prev, curr = head, head.next
    inserted = False

    while True:
        if prev.val <= insertVal <= curr.val:
            prev.next = Node(insertVal, curr)
            inserted = True
        elif prev.val > curr.val:
            if insertVal >= prev.val or insertVal <= curr.val:
                prev.next = Node(insertVal, curr)
                inserted = True
        prev, curr = curr, curr.next

        if prev == head or inserted:
            break

    if not inserted:
        prev.next = Node(insertVal, curr)

    return head
```
1. If the given `head` is `null`, we create a new node with the value `insertVal`, make it circular by pointing its `next` to itself, and return it.

2. If `head` is not `null`, we start iterating the list from head to the next node.

3. If `insertVal` fits between the values of the previous and current nodes considering the sorted list, add a new node with the value `insertVal` between previous and current nodes.

4. If the value of the previous node is greater than the value of the current node (it means we reached the end of the list and looped back to the start) AND `insertVal` fits in that range, add a new node with the value `insertVal` between those nodes.

5. If we complete the iteration without inserting the node, insert a new node with the value `insertVal` between the last previous node and its next.

6. Return the original given `head`.

## A solution in Javascript

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

function insert(head, insertVal) {
    if (head === null) {
        const newNode = new Node(insertVal);
        newNode.next = newNode;
        return newNode;
    }

    let prev = head;
    let curr = head.next;
    let inserted = false;

    do {
        if (prev.val <= insertVal && insertVal <= curr.val) {
            prev.next = new Node(insertVal, curr);
            inserted = true;
        } else if (prev.val > curr.val) {
            if (insertVal >= prev.val || insertVal <= curr.val) {
                prev.next = new Node(insertVal, curr);
                inserted = true;
            }
        }
        prev = curr;
        curr = curr.next;
    } while (prev !== head && !inserted);

    if (!inserted) {
        prev.next = new Node(insertVal, curr);
    }

    return head;
}
```
1. If the given `head` is `null`, we create a new node with the value `insertVal`, make it circular by pointing its `next` to itself, and return it.

2. If `head` is not `null`, we start iterating the list from head to the next node.

3. If `insertVal` fits between the values of the previous and current nodes considering the sorted list, add a new node with the value `insertVal` between previous and current nodes.

4. If the value of the previous node is greater than the value of the current node (it means we reached the end of the list and looped back to the start) AND `insertVal` fits in that range, add a new node with the value `insertVal` between those nodes.

5. If we complete the iteration without inserting the node, insert a new node with the value `insertVal` between the last previous node and its next.

6. Return the original given `head`.


# To Lower Case

- slug: to-lower-case
- difficulty: Easy

Given a string `s`, return _the string after replacing every uppercase letter with the same lowercase letter_.

**Example 1:**

**Input:** s =  "Hello "
**Output:**  "hello "

**Example 2:**

**Input:** s =  "here "
**Output:**  "here "

**Example 3:**

**Input:** s =  "LOVELY "
**Output:**  "lovely "

**Constraints:**

*   `1 <= s.length <= 100`
*   `s` consists of printable ASCII characters.

## A solution in Java

```java
public String toLowerCase(String s) {
    char[] chars = s.toCharArray();
    for (int i = 0; i < chars.length; i++) {
        if (chars[i] >= 'A' && chars[i] <= 'Z') {
            chars[i] = (char)(chars[i] - 'A' + 'a');
        }
    }
    return new String(chars);
}
```
The algorithm goes through each character in the input string and checks if the character is an uppercase letter. If it is, it converts the letter to lowercase, otherwise it keeps the character unchanged. In C++ and Java, we use a loop to go through each character and update it in-place. In Python, the built-in `str.lower()` function is used. In JavaScript, we need to create a new string by concatenating the resulting characters. For each language, the modified string is returned.

## A solution in C++

```cpp
#include <string>

std::string toLowerCase(std::string s) {
    for (char& c : s) {
        if (c >= 'A' && c <= 'Z') {
            c = c - 'A' + 'a';
        }
    }
    return s;
}
```
The algorithm goes through each character in the input string and checks if the character is an uppercase letter. If it is, it converts the letter to lowercase, otherwise it keeps the character unchanged. In C++ and Java, we use a loop to go through each character and update it in-place. In Python, the built-in `str.lower()` function is used. In JavaScript, we need to create a new string by concatenating the resulting characters. For each language, the modified string is returned.

## A solution in Python

```python
def toLowerCase(s: str) -> str:
    return s.lower()
```
The algorithm goes through each character in the input string and checks if the character is an uppercase letter. If it is, it converts the letter to lowercase, otherwise it keeps the character unchanged. In C++ and Java, we use a loop to go through each character and update it in-place. In Python, the built-in `str.lower()` function is used. In JavaScript, we need to create a new string by concatenating the resulting characters. For each language, the modified string is returned.

## A solution in Javascript

```javascript
function toLowerCase(s) {
    let result = '';
    for (let i = 0; i < s.length; i++) {
        let charCode = s.charCodeAt(i);
        if (charCode >= 65 && charCode <= 90) {
            charCode += 32;
        }
        result += String.fromCharCode(charCode);
    }
    return result;
}
```
The algorithm goes through each character in the input string and checks if the character is an uppercase letter. If it is, it converts the letter to lowercase, otherwise it keeps the character unchanged. In C++ and Java, we use a loop to go through each character and update it in-place. In Python, the built-in `str.lower()` function is used. In JavaScript, we need to create a new string by concatenating the resulting characters. For each language, the modified string is returned.