# Jump Game V

- slug: jump-game-v
- difficulty: Hard

Given an array of integers `arr` and an integer `d`. In one step you can jump from index `i` to index:

*   `i + x` where: `i + x < arr.length` and `0 < x <= d`.
*   `i - x` where: `i - x >= 0` and `0 < x <= d`.

In addition, you can only jump from index `i` to index `j` if `arr[i] > arr[j]` and `arr[i] > arr[k]` for all indices `k` between `i` and `j` (More formally `min(i, j) < k < max(i, j)`).

You can choose any index of the array and start jumping. Return _the maximum number of indices_ you can visit.

Notice that you can not jump outside of the array at any time.

**Example 1:**

**Input:** arr = \[6,4,14,6,8,13,9,7,10,6,12\], d = 2
**Output:** 4
**Explanation:** You can start at index 10. You can jump 10 --> 8 --> 6 --> 7 as shown.
Note that if you start at index 6 you can only jump to index 7. You cannot jump to index 5 because 13 > 9. You cannot jump to index 4 because index 5 is between index 4 and 6 and 13 > 9.
Similarly You cannot jump from index 3 to index 2 or index 1.

**Example 2:**

**Input:** arr = \[3,3,3,3,3\], d = 3
**Output:** 1
**Explanation:** You can start at any index. You always cannot jump to any index.

**Example 3:**

**Input:** arr = \[7,6,5,4,3,2,1\], d = 1
**Output:** 7
**Explanation:** Start at index 0. You can visit all the indicies.

**Constraints:**

*   `1 <= arr.length <= 1000`
*   `1 <= arr[i] <= 105`
*   `1 <= d <= arr.length`

## A solution in Java

```java
import java.util.concurrent.locks.*;

class DiningPhilosophers {
    private final ReentrantLock[] locks = new ReentrantLock[5];
    private final Condition[] notBusy = new Condition[5];

    public DiningPhilosophers() {
        for (int i = 0; i < 5; i++) {
            locks[i] = new ReentrantLock();
            notBusy[i] = locks[i].newCondition();
        }
    }

    public void wantsToEat(int philosopher,
                            Runnable pickLeftFork,
                            Runnable pickRightFork,
                            Runnable eat,
                            Runnable putLeftFork,
                            Runnable putRightFork) throws InterruptedException {
        int leftFork = philosopher;
        int rightFork = (philosopher + 1) % 5;

        locks[leftFork].lock();
        try {
            while (!locks[rightFork].tryLock()) {
                notBusy[leftFork].await();
            }
            pickLeftFork.run();

            try {
                pickRightFork.run();
                eat.run();
                putRightFork.run();
            } finally {
                locks[rightFork].unlock();
            }
            notBusy[rightFork].signalAll();

            putLeftFork.run();
        } finally {
            locks[leftFork].unlock();
        }
        notBusy[leftFork].signalAll();
    }
}
```
The algorithm uses one mutex for each fork and a condition variable for each philosopher to manage the synchronization of accessing forks. When a philosopher starts to eat, they first lock the mutex of the left fork and indicate that the corresponding fork is busy. After that, they try to lock the mutex of the right fork. If they are able to lock the right mutex, they can eat. After eating, they release the mutex of the right fork and indicate that it is not busy. Finally, the mutex of the left fork is unlocked.

To avoid deadlocks, a philosopher will only proceed with eating if they can lock the mutex of the right fork while holding the mutex of the left fork. If they can't lock the right mutex, they will wait using a condition variable until the right mutex is available. After eating, the philosopher will signal to other philosophers that they have finished eating and the forks are available.

The main idea of this approach is to ensure that a philosopher is always able to acquire both forks without causing deadlocks or starving. By waiting on the condition variable until both forks are available, we prevent deadlocks and ensure fairness among the philosophers. This behavior is obtained by having each philosopher try to grab its left fork first and then its right fork, only eating once it has acquired both. This ensures that philosophers will not deadlock by all grabbing one fork and waiting for another.

## A solution in C++

```cpp
#include <mutex>
#include <condition_variable>

class DiningPhilosophers {
    std::mutex forks[5];
    std::condition_variable not_busy[5];

public:
    void wantsToEat(int philosopher,
                    std::function<void()> pickLeftFork,
                    std::function<void()> pickRightFork,
                    std::function<void()> eat,
                    std::function<void()> putLeftFork,
                    std::function<void()> putRightFork) {
        int left_fork = philosopher;
        int right_fork = (philosopher + 1) % 5;

        {
            std::unique_lock<std::mutex> lock(forks[left_fork]);
            not_busy[left_fork].wait(lock, [&] { return !forks[right_fork].try_lock(); });
            pickLeftFork();

            std::unique_lock<std::mutex> right_lock(forks[right_fork], std::adopt_lock);
            pickRightFork();
            eat();

            putRightFork();
            right_lock.unlock();
            not_busy[right_fork].notify_all();
        }

        putLeftFork();
        not_busy[left_fork].notify_all();
    }
};
```
The algorithm uses one mutex for each fork and a condition variable for each philosopher to manage the synchronization of accessing forks. When a philosopher starts to eat, they first lock the mutex of the left fork and indicate that the corresponding fork is busy. After that, they try to lock the mutex of the right fork. If they are able to lock the right mutex, they can eat. After eating, they release the mutex of the right fork and indicate that it is not busy. Finally, the mutex of the left fork is unlocked.

To avoid deadlocks, a philosopher will only proceed with eating if they can lock the mutex of the right fork while holding the mutex of the left fork. If they can't lock the right mutex, they will wait using a condition variable until the right mutex is available. After eating, the philosopher will signal to other philosophers that they have finished eating and the forks are available.

The main idea of this approach is to ensure that a philosopher is always able to acquire both forks without causing deadlocks or starving. By waiting on the condition variable until both forks are available, we prevent deadlocks and ensure fairness among the philosophers. This behavior is obtained by having each philosopher try to grab its left fork first and then its right fork, only eating once it has acquired both. This ensures that philosophers will not deadlock by all grabbing one fork and waiting for another.

## A solution in Python

```python
import threading

class DiningPhilosophers:
    def __init__(self):
        self.forks = [threading.Lock() for _ in range(5)]
        self.not_busy = [threading.Condition(self.forks[i]) for i in range(5)]

    def wantsToEat(self, philosopher: int, pickLeftFork: 'Callable[[], None]', pickRightFork: 'Callable[[], None]', eat: 'Callable[[], None]', putLeftFork: 'Callable[[], None]', putRightFork: 'Callable[[], None]') -> None:
        left_fork = philosopher
        right_fork = (philosopher + 1) % 5

        with self.forks[left_fork]:
            with self.not_busy[left_fork]:
                while not self.forks[right_fork].acquire(blocking=False):
                    self.not_busy[left_fork].wait()
            pickLeftFork()

            with self.forks[right_fork]:
                pickRightFork()
                eat()
                putRightFork()
                self.forks[right_fork].release()
                with self.not_busy[right_fork]:
                    self.not_busy[right_fork].notify_all()

            putLeftFork()
            self.not_busy[left_fork].notify_all()
```
The algorithm uses one mutex for each fork and a condition variable for each philosopher to manage the synchronization of accessing forks. When a philosopher starts to eat, they first lock the mutex of the left fork and indicate that the corresponding fork is busy. After that, they try to lock the mutex of the right fork. If they are able to lock the right mutex, they can eat. After eating, they release the mutex of the right fork and indicate that it is not busy. Finally, the mutex of the left fork is unlocked.

To avoid deadlocks, a philosopher will only proceed with eating if they can lock the mutex of the right fork while holding the mutex of the left fork. If they can't lock the right mutex, they will wait using a condition variable until the right mutex is available. After eating, the philosopher will signal to other philosophers that they have finished eating and the forks are available.

The main idea of this approach is to ensure that a philosopher is always able to acquire both forks without causing deadlocks or starving. By waiting on the condition variable until both forks are available, we prevent deadlocks and ensure fairness among the philosophers. This behavior is obtained by having each philosopher try to grab its left fork first and then its right fork, only eating once it has acquired both. This ensures that philosophers will not deadlock by all grabbing one fork and waiting for another.

## A solution in Javascript

```javascript
class DiningPhilosophers {
    constructor() {
        this.forks = Array.from({ length: 5 }, () => new Mutex());
        this.notBusy = Array.from({ length: 5 }, (_, i) => new ConditionVariable(this.forks[i]));
    }

    async wantsToEat(philosopher, pickLeftFork, pickRightFork, eat, putLeftFork, putRightFork) {
        const leftFork = philosopher;
        const rightFork = (philosopher + 1) % 5;

        await this.forks[leftFork].lock();
        try {
            await this.notBusy[leftFork].wait(async () => !(await this.forks[rightFork].tryLock()));
            pickLeftFork();

            try {
                await this.forks[rightFork].lock();
                pickRightFork();
                eat();
                putRightFork();
                this.forks[rightFork].unlock();
                this.notBusy[rightFork].signalAll();

                putLeftFork();
            } finally {
                this.forks[leftFork].unlock();
            }
        } finally {
            this.notBusy[leftFork].signalAll();
        }
    }
}
```
The algorithm uses one mutex for each fork and a condition variable for each philosopher to manage the synchronization of accessing forks. When a philosopher starts to eat, they first lock the mutex of the left fork and indicate that the corresponding fork is busy. After that, they try to lock the mutex of the right fork. If they are able to lock the right mutex, they can eat. After eating, they release the mutex of the right fork and indicate that it is not busy. Finally, the mutex of the left fork is unlocked.

To avoid deadlocks, a philosopher will only proceed with eating if they can lock the mutex of the right fork while holding the mutex of the left fork. If they can't lock the right mutex, they will wait using a condition variable until the right mutex is available. After eating, the philosopher will signal to other philosophers that they have finished eating and the forks are available.

The main idea of this approach is to ensure that a philosopher is always able to acquire both forks without causing deadlocks or starving. By waiting on the condition variable until both forks are available, we prevent deadlocks and ensure fairness among the philosophers. This behavior is obtained by having each philosopher try to grab its left fork first and then its right fork, only eating once it has acquired both. This ensures that philosophers will not deadlock by all grabbing one fork and waiting for another.


# Number of Steps to Reduce a Number to Zero

- slug: number-of-steps-to-reduce-a-number-to-zero
- difficulty: Easy

Given an integer `num`, return _the number of steps to reduce it to zero_.

In one step, if the current number is even, you have to divide it by `2`, otherwise, you have to subtract `1` from it.

**Example 1:**

**Input:** num = 14
**Output:** 6
**Explanation:**
Step 1) 14 is even; divide by 2 and obtain 7.
Step 2) 7 is odd; subtract 1 and obtain 6.
Step 3) 6 is even; divide by 2 and obtain 3.
Step 4) 3 is odd; subtract 1 and obtain 2.
Step 5) 2 is even; divide by 2 and obtain 1.
Step 6) 1 is odd; subtract 1 and obtain 0.

**Example 2:**

**Input:** num = 8
**Output:** 4
**Explanation:**
Step 1) 8 is even; divide by 2 and obtain 4.
Step 2) 4 is even; divide by 2 and obtain 2.
Step 3) 2 is even; divide by 2 and obtain 1.
Step 4) 1 is odd; subtract 1 and obtain 0.

**Example 3:**

**Input:** num = 123
**Output:** 12

**Constraints:**

*   `0 <= num <= 106`

## A solution in Java

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

public List<List<Integer>> queensAttacktheKing(int[][] queens, int[] king) {
    List<List<Integer>> result = new ArrayList<>();
    for (int x = -1; x <= 1; x++) {
        for (int y = -1; y <= 1; y++) {
            if (x == 0 && y == 0) continue;
            int posX = king[0] + x;
            int posY = king[1] + y;
            while (posX >= 0 && posY >= 0 && posX < 8 && posY < 8) {
                for (int[] queen : queens) {
                    if (posX == queen[0] && posY == queen[1]) {
                        List<Integer> attackingQueen = new ArrayList<>();
                        attackingQueen.add(queen[0]);
                        attackingQueen.add(queen[1]);
                        result.add(attackingQueen);
                        break;
                    }
                }
                posX += x;
                posY += y;
            }
        }
    }
    return result;
}
```
The algorithm consists of the following steps:
1. For each direction, including diagonals, create a loop that starts from the position of the King.
2. Iterate through the loop, going one cell at a time in the chosen direction.
3. For each iteration, check if there is a queen on that cell by comparing it to the coordinates of the queens in the input array.
4. If a queen is found in that cell, add the coordinates of that queen to the result list and break the inner loop.
5. Continue to the next direction.

This algorithm ensures that every possible direction is checked from the King's position, and if there's a queen in that direction, it will be added to the resulting list. This way, we get all the queens that can attack the King.

## A solution in C++

```cpp
#include <vector>

std::vector<std::vector<int>> queensAttacktheKing(std::vector<std::vector<int>>& queens, std::vector<int>& king) {
    std::vector<std::vector<int>> result;
    for (int x = -1; x <= 1; x++) {
        for (int y = -1; y <= 1; y++) {
            if (x == 0 && y == 0) continue;
            int posX = king[0] + x;
            int posY = king[1] + y;
            while (posX >= 0 && posY >= 0 && posX < 8 && posY < 8) {
                for (std::vector<int>& queen : queens) {
                    if (posX == queen[0] && posY == queen[1]) {
                        result.push_back({queen[0], queen[1]});
                        break;
                    }
                }
                posX += x;
                posY += y;
            }
        }
    }
    return result;
}
```
The algorithm consists of the following steps:
1. For each direction, including diagonals, create a loop that starts from the position of the King.
2. Iterate through the loop, going one cell at a time in the chosen direction.
3. For each iteration, check if there is a queen on that cell by comparing it to the coordinates of the queens in the input array.
4. If a queen is found in that cell, add the coordinates of that queen to the result list and break the inner loop.
5. Continue to the next direction.

This algorithm ensures that every possible direction is checked from the King's position, and if there's a queen in that direction, it will be added to the resulting list. This way, we get all the queens that can attack the King.

## A solution in Python

```python
def queensAttacktheKing(queens, king):
    result = []
    for x in range(-1, 2):
        for y in range(-1, 2):
            if x == 0 and y == 0:
                continue
            posX, posY = king[0] + x, king[1] + y
            while 0 <= posX < 8 and 0 <= posY < 8:
                for queen in queens:
                    if posX == queen[0] and posY == queen[1]:
                        result.append([queen[0], queen[1]])
                        break
                posX += x
                posY += y
    return result
```
The algorithm consists of the following steps:
1. For each direction, including diagonals, create a loop that starts from the position of the King.
2. Iterate through the loop, going one cell at a time in the chosen direction.
3. For each iteration, check if there is a queen on that cell by comparing it to the coordinates of the queens in the input array.
4. If a queen is found in that cell, add the coordinates of that queen to the result list and break the inner loop.
5. Continue to the next direction.

This algorithm ensures that every possible direction is checked from the King's position, and if there's a queen in that direction, it will be added to the resulting list. This way, we get all the queens that can attack the King.

## A solution in Javascript

```javascript
function queensAttacktheKing(queens, king) {
    const result = [];
    for (let x = -1; x <= 1; x++) {
        for (let y = -1; y <= 1; y++) {
            if (x === 0 && y === 0) continue;
            let posX = king[0] + x;
            let posY = king[1] + y;
            while (posX >= 0 && posY >= 0 && posX < 8 && posY < 8) {
                for (const queen of queens) {
                    if (posX === queen[0] && posY === queen[1]) {
                        result.push([queen[0], queen[1]]);
                        break;
                    }
                }
                posX += x;
                posY += y;
            }
        }
    }
    return result;
}
```
The algorithm consists of the following steps:
1. For each direction, including diagonals, create a loop that starts from the position of the King.
2. Iterate through the loop, going one cell at a time in the chosen direction.
3. For each iteration, check if there is a queen on that cell by comparing it to the coordinates of the queens in the input array.
4. If a queen is found in that cell, add the coordinates of that queen to the result list and break the inner loop.
5. Continue to the next direction.

This algorithm ensures that every possible direction is checked from the King's position, and if there's a queen in that direction, it will be added to the resulting list. This way, we get all the queens that can attack the King.


# Number of Sub-arrays of Size K and Average Greater than or Equal to Threshold

- slug: number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold
- difficulty: Medium

Given an array of integers `arr` and two integers `k` and `threshold`, return _the number of sub-arrays of size_ `k` _and average greater than or equal to_ `threshold`.

**Example 1:**

**Input:** arr = \[2,2,2,2,5,5,5,8\], k = 3, threshold = 4
**Output:** 3
**Explanation:** Sub-arrays \[2,5,5\],\[5,5,5\] and \[5,5,8\] have averages 4, 5 and 6 respectively. All other sub-arrays of size 3 have averages less than 4 (the threshold).

**Example 2:**

**Input:** arr = \[11,13,17,23,29,31,7,5,2,3\], k = 3, threshold = 5
**Output:** 6
**Explanation:** The first 6 sub-arrays of size 3 have averages greater than 5. Note that averages are not integers.

**Constraints:**

*   `1 <= arr.length <= 105`
*   `1 <= arr[i] <= 104`
*   `1 <= k <= arr.length`
*   `0 <= threshold <= 104`

## A solution in Java

```java
public int dieSimulator(int n, int[] rollMax) {
    int MOD = (int)1e9 + 7;
    int[][] dp = new int[6][n + 1];
    int[] sum = new int[n + 1];

    for (int i = 0; i < 6; i++) dp[i][1] = 1;
    sum[1] = 6;

    for (int j = 2; j <= n; j++) {
        int cur_sum = 0;
        for (int i = 0; i < 6; i++) {
            dp[i][j] = sum[j - 1];
            if (j - rollMax[i] - 1 >= 0) {
                dp[i][j] = (int)(((long)dp[i][j] - sum[j - rollMax[i] - 1] + MOD) % MOD);
                if (j - rollMax[i] - 1 >= 1) {
                    dp[i][j] = (dp[i][j] + dp[i][j - rollMax[i] - 1]) % MOD;
                }
            }
            cur_sum = (cur_sum + dp[i][j]) % MOD;
        }
        sum[j] = cur_sum;
    }

    return sum[n];
}
```
The algorithm uses Dynamic Programming to solve this problem. We initialize a 2D array `dp` with 6 rows (corresponding to the numbers on the die) and n + 1 columns. We fill the first column of the `dp` array with all 1s since there's only one way for each number to occur once. We also initialize an array `sum` to store the cumulative sum.

We iterate through the rolls (2 to n) and for each number on the die (0 to 5), we update the `dp[i][j]` value. The general idea is that the total unique sequences ending in each die number i after j rolls is the sum of all sequences after j - 1 rolls minus the sequences that would violate the `rollMax[i]` constraint. We update the running sum for each roll and keep track of it in `sum`.

After traversing all rolls, the `sum[n]` will contain the number of distinct sequences that can be obtained with exactly n rolls, which we return as the output.

## A solution in C++

```cpp
#include <vector>

const int MOD = 1000000007;

int dieSimulator(int n, std::vector<int>& rollMax) {
    std::vector<std::vector<int>> dp(6, std::vector<int>(n + 1, 0));
    std::vector<int> sum(n + 1, 0);

    for (int i = 0; i < 6; i++) dp[i][1] = 1;
    sum[1] = 6;

    for (int j = 2; j <= n; j++) {
        int cur_sum = 0;
        for (int i = 0; i < 6; i++) {
            dp[i][j] = sum[j - 1];
            if (j - rollMax[i] - 1 >= 0) {
                dp[i][j] = (dp[i][j] - sum[j - rollMax[i] - 1] + MOD) % MOD;
                if (j - rollMax[i] - 1 >= 1) {
                    dp[i][j] = (dp[i][j] + dp[i][j - rollMax[i] - 1]) % MOD;
                }
            }
            cur_sum = (cur_sum + dp[i][j]) % MOD;
        }
        sum[j] = cur_sum;
    }

    return sum[n];
}
```
The algorithm uses Dynamic Programming to solve this problem. We initialize a 2D array `dp` with 6 rows (corresponding to the numbers on the die) and n + 1 columns. We fill the first column of the `dp` array with all 1s since there's only one way for each number to occur once. We also initialize an array `sum` to store the cumulative sum.

We iterate through the rolls (2 to n) and for each number on the die (0 to 5), we update the `dp[i][j]` value. The general idea is that the total unique sequences ending in each die number i after j rolls is the sum of all sequences after j - 1 rolls minus the sequences that would violate the `rollMax[i]` constraint. We update the running sum for each roll and keep track of it in `sum`.

After traversing all rolls, the `sum[n]` will contain the number of distinct sequences that can be obtained with exactly n rolls, which we return as the output.

## A solution in Python

```python
def dieSimulator(n, rollMax):
    MOD = 10**9 + 7
    dp = [[0] * (n + 1) for _ in range(6)]
    sum_dp = [0] * (n + 1)

    for i in range(6):
        dp[i][1] = 1
    sum_dp[1] = 6

    for j in range(2, n + 1):
        cur_sum = 0
        for i in range(6):
            dp[i][j] = sum_dp[j - 1]
            if j - rollMax[i] - 1 >= 0:
                dp[i][j] = (dp[i][j] - sum_dp[j - rollMax[i] - 1] + MOD) % MOD
                if j - rollMax[i] - 1 >= 1:
                    dp[i][j] = (dp[i][j] + dp[i][j - rollMax[i] - 1]) % MOD
            cur_sum = (cur_sum + dp[i][j]) % MOD
        sum_dp[j] = cur_sum

    return sum_dp[n]
```
The algorithm uses Dynamic Programming to solve this problem. We initialize a 2D array `dp` with 6 rows (corresponding to the numbers on the die) and n + 1 columns. We fill the first column of the `dp` array with all 1s since there's only one way for each number to occur once. We also initialize an array `sum` to store the cumulative sum.

We iterate through the rolls (2 to n) and for each number on the die (0 to 5), we update the `dp[i][j]` value. The general idea is that the total unique sequences ending in each die number i after j rolls is the sum of all sequences after j - 1 rolls minus the sequences that would violate the `rollMax[i]` constraint. We update the running sum for each roll and keep track of it in `sum`.

After traversing all rolls, the `sum[n]` will contain the number of distinct sequences that can be obtained with exactly n rolls, which we return as the output.

## A solution in Javascript

```javascript
function dieSimulator(n, rollMax) {
    const MOD = 1000000007;
    const dp = Array.from({ length: 6 }, () => Array(n + 1).fill(0));
    const sum = Array(n + 1).fill(0);

    for (let i = 0; i < 6; i++) dp[i][1] = 1;
    sum[1] = 6;

    for (let j = 2; j <= n; j++) {
        let cur_sum = 0;
        for (let i = 0; i < 6; i++) {
            dp[i][j] = sum[j - 1];
            if (j - rollMax[i] - 1 >= 0) {
                dp[i][j] = (dp[i][j] - sum[j - rollMax[i] - 1] + MOD) % MOD;
                if (j - rollMax[i] - 1 >= 1) {
                    dp[i][j] = (dp[i][j] + dp[i][j - rollMax[i] - 1]) % MOD;
                }
            }
            cur_sum = (cur_sum + dp[i][j]) % MOD;
        }
        sum[j] = cur_sum;
    }

    return sum[n];
}
```
The algorithm uses Dynamic Programming to solve this problem. We initialize a 2D array `dp` with 6 rows (corresponding to the numbers on the die) and n + 1 columns. We fill the first column of the `dp` array with all 1s since there's only one way for each number to occur once. We also initialize an array `sum` to store the cumulative sum.

We iterate through the rolls (2 to n) and for each number on the die (0 to 5), we update the `dp[i][j]` value. The general idea is that the total unique sequences ending in each die number i after j rolls is the sum of all sequences after j - 1 rolls minus the sequences that would violate the `rollMax[i]` constraint. We update the running sum for each roll and keep track of it in `sum`.

After traversing all rolls, the `sum[n]` will contain the number of distinct sequences that can be obtained with exactly n rolls, which we return as the output.


# Angle Between Hands of a Clock

- slug: angle-between-hands-of-a-clock
- difficulty: Medium

Given two numbers, `hour` and `minutes`, return _the smaller angle (in degrees) formed between the_ `hour` _and the_ `minute` _hand_.

Answers within `10-5` of the actual value will be accepted as correct.

**Example 1:**

**Input:** hour = 12, minutes = 30
**Output:** 165

**Example 2:**

**Input:** hour = 3, minutes = 30
**Output:** 75

**Example 3:**

**Input:** hour = 3, minutes = 15
**Output:** 7.5

**Constraints:**

*   `1 <= hour <= 12`
*   `0 <= minutes <= 59`

## A solution in Java

```java
public int maxEqualFreq(int[] nums) {
    Map<Integer, Integer> count = new HashMap<>();
    Map<Integer, Integer> freq = new HashMap<>();
    int max_len = 0, max_freq = 0;
    for (int i = 0; i < nums.length; i++) {
        count.put(nums[i], count.getOrDefault(nums[i], 0) + 1);
        freq.put(count.get(nums[i]) - 1, freq.getOrDefault(count.get(nums[i]) - 1, 0) - 1);
        freq.put(count.get(nums[i]), freq.getOrDefault(count.get(nums[i]), 0) + 1);

        max_freq = Math.max(max_freq, count.get(nums[i]));
        if (max_freq * (i + 1) == i || max_freq * (freq.getOrDefault(max_freq - 1, 0) + 1) + (max_freq - 1) * freq.getOrDefault(max_freq - 1, 0) == i) {
            max_len = i + 1;
        }
    }
    return max_len;
}
```
The algorithm uses two hash maps: `count` to store the occurrence count (frequency) of each number in nums, and `freq` to store the count of numbers having the same frequency. For each element in nums, the algorithm updates both count and freq maps, and keeps track of the maximum frequency found so far. The algorithm calculates the max_len by checking two conditions:
1. If the product of max_freq and (i + 1) equals i, which means that after removing one element, all elements have the same frequency.
2. If the product of max_freq and (number of elements having the frequency max_freq - 1 plus 1) plus the product of (max_freq - 1) and (number of elements having the frequency max_freq - 1) equal i. This condition means that after removing one element, all elements have either the same frequency or a difference of 1 in their frequencies.
If either of the two conditions is met, the current index + 1 is considered as the maximum length of a valid prefix. The algorithm iterates through nums to find the answer.

## A solution in C++

```cpp
int maxEqualFreq(vector<int>& nums) {
    unordered_map<int, int> count, freq;
    int max_len = 0, max_freq = 0;
    for (int i = 0; i < nums.size(); i++) {
        count[nums[i]]++;
        freq[count[nums[i]] - 1]--;
        freq[count[nums[i]]]++;

        max_freq = max(max_freq, count[nums[i]]);
        if (max_freq * (i + 1) == i || max_freq * (freq[max_freq - 1] + 1) + (max_freq - 1) * freq[max_freq - 1] == i) {
            max_len = i + 1;
        }
    }
    return max_len;
}
```
The algorithm uses two hash maps: `count` to store the occurrence count (frequency) of each number in nums, and `freq` to store the count of numbers having the same frequency. For each element in nums, the algorithm updates both count and freq maps, and keeps track of the maximum frequency found so far. The algorithm calculates the max_len by checking two conditions:
1. If the product of max_freq and (i + 1) equals i, which means that after removing one element, all elements have the same frequency.
2. If the product of max_freq and (number of elements having the frequency max_freq - 1 plus 1) plus the product of (max_freq - 1) and (number of elements having the frequency max_freq - 1) equal i. This condition means that after removing one element, all elements have either the same frequency or a difference of 1 in their frequencies.
If either of the two conditions is met, the current index + 1 is considered as the maximum length of a valid prefix. The algorithm iterates through nums to find the answer.

## A solution in Python

```python
def maxEqualFreq(nums):
    count, freq = {}, {}
    max_len, max_freq = 0, 0
    for i, num in enumerate(nums):
        count[num] = count.get(num, 0) + 1
        freq[count[num] - 1] = freq.get(count[num] - 1, 0) - 1
        freq[count[num]] = freq.get(count[num], 0) + 1

        max_freq = max(max_freq, count[num])
        if max_freq * (i + 1) == i or max_freq * (freq.get(max_freq - 1, 0) + 1) + (max_freq - 1) * freq.get(max_freq - 1, 0) == i:
            max_len = i + 1
    return max_len
```
The algorithm uses two hash maps: `count` to store the occurrence count (frequency) of each number in nums, and `freq` to store the count of numbers having the same frequency. For each element in nums, the algorithm updates both count and freq maps, and keeps track of the maximum frequency found so far. The algorithm calculates the max_len by checking two conditions:
1. If the product of max_freq and (i + 1) equals i, which means that after removing one element, all elements have the same frequency.
2. If the product of max_freq and (number of elements having the frequency max_freq - 1 plus 1) plus the product of (max_freq - 1) and (number of elements having the frequency max_freq - 1) equal i. This condition means that after removing one element, all elements have either the same frequency or a difference of 1 in their frequencies.
If either of the two conditions is met, the current index + 1 is considered as the maximum length of a valid prefix. The algorithm iterates through nums to find the answer.

## A solution in Javascript

```javascript
function maxEqualFreq(nums) {
    let count = new Map(), freq = new Map();
    let max_len = 0, max_freq = 0;
    for (let i = 0; i < nums.length; i++) {
        count.set(nums[i], (count.get(nums[i]) || 0) + 1);
        freq.set(count.get(nums[i]) - 1, (freq.get(count.get(nums[i]) - 1) || 0) - 1);
        freq.set(count.get(nums[i]), (freq.get(count.get(nums[i])) || 0) + 1);

        max_freq = Math.max(max_freq, count.get(nums[i]));
        if (max_freq * (i + 1) == i || max_freq * ((freq.get(max_freq - 1) || 0) + 1) + (max_freq - 1) * (freq.get(max_freq - 1) || 0) == i) {
            max_len = i + 1;
        }
    }
    return max_len;
}
```
The algorithm uses two hash maps: `count` to store the occurrence count (frequency) of each number in nums, and `freq` to store the count of numbers having the same frequency. For each element in nums, the algorithm updates both count and freq maps, and keeps track of the maximum frequency found so far. The algorithm calculates the max_len by checking two conditions:
1. If the product of max_freq and (i + 1) equals i, which means that after removing one element, all elements have the same frequency.
2. If the product of max_freq and (number of elements having the frequency max_freq - 1 plus 1) plus the product of (max_freq - 1) and (number of elements having the frequency max_freq - 1) equal i. This condition means that after removing one element, all elements have either the same frequency or a difference of 1 in their frequencies.
If either of the two conditions is met, the current index + 1 is considered as the maximum length of a valid prefix. The algorithm iterates through nums to find the answer.


# Jump Game IV

- slug: jump-game-iv
- difficulty: Hard

Given an array of integers `arr`, you are initially positioned at the first index of the array.

In one step you can jump from index `i` to index:

*   `i + 1` where: `i + 1 < arr.length`.
*   `i - 1` where: `i - 1 >= 0`.
*   `j` where: `arr[i] == arr[j]` and `i != j`.

Return _the minimum number of steps_ to reach the **last index** of the array.

Notice that you can not jump outside of the array at any time.

**Example 1:**

**Input:** arr = \[100,-23,-23,404,100,23,23,23,3,404\]
**Output:** 3
**Explanation:** You need three jumps from index 0 --> 4 --> 3 --> 9. Note that index 9 is the last index of the array.

**Example 2:**

**Input:** arr = \[7\]
**Output:** 0
**Explanation:** Start index is the last index. You do not need to jump.

**Example 3:**

**Input:** arr = \[7,6,9,6,9,6,9,7\]
**Output:** 1
**Explanation:** You can jump directly from index 0 to index 7 which is last index of the array.

**Constraints:**

*   `1 <= arr.length <= 5 * 104`
*   `-108 <= arr[i] <= 108`

## A solution in Java

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

public int minJumps(int[] arr) {
    int n = arr.length;
    if (n <= 1) return 0;

    HashMap<Integer, LinkedList<Integer>> valueIndices = new HashMap<>();

    for (int i = 0; i < n; ++i) {
        valueIndices.computeIfAbsent(arr[i], v -> new LinkedList<>()).add(i);
    }

    Queue<Integer> queue = new LinkedList<>();
    boolean[] visited = new boolean[n];

    queue.offer(0);
    visited[0] = true;
    int steps = 0;

    while (!queue.isEmpty()) {
        int size = queue.size();

        for (int i = 0; i < size; ++i) {
            int index = queue.poll();

            if (index == n - 1) return steps;

            if (index > 0 && !visited[index - 1]) {
                queue.offer(index - 1);
                visited[index - 1] = true;
            }

            if (index < n - 1 && !visited[index + 1]) {
                queue.offer(index + 1);
                visited[index + 1] = true;
            }

            for (int neighbor : valueIndices.get(arr[index])) {
                if (!visited[neighbor]) {
                    queue.offer(neighbor);
                    visited[neighbor] = true;
                }
            }

            valueIndices.get(arr[index]).clear();
        }

        ++steps;
    }

    return -1;
}
```
The algorithm to solve this problem is using the Breadth-First Search (BFS) approach.

1. First, iterate through the `arr` and create a hash map (`value_indices`) to map each unique value to their indices in the array.
2. Initialize the BFS queue `q`, the visited array `visited`, and steps counter `steps`.
3. While queue `q` is not empty, perform the following:
   a. Set the `size` variable as the current length of the queue `q`.
   b. Iterate through the `size` of the queue `q`. For each iteration:
      i. Pop the front of the queue `q` and assign the popped index to `index`.
      ii. If the popped index is the last index of the array, return the steps counter.
      iii. Check the valid neighbors `(index-1, index+1, or the same value as arr[index])` that haven't been visited yet:
         - If it's a valid neighbor and not visited before, mark the neighbor as visited and push the neighbor to the queue `q`.
      iv. Clear the value_indices entry for this index, as we don't want to revisit it.
   c. Increase the steps counter by 1.
4. If the last index is not reached, return -1. (This will not happen in the given constraints)

In each programming language, the major difference is in the syntax and data structures used to implement this algorithm. The key points of the language-specific implementations are as follows:

- In C++, we use `std::vector`, `std::queue`, `std::unordered_map`, and `std::vector<bool>` for array manipulation and storage.
- In Java, we use `java.util.HashMap`, `java.util.LinkedList` for both queue and mapping values, and a boolean array for storing visited status.
- In Python, we use Python's `list` and `collections.defaultdict` for mapping values and storing visited status.
- In JavaScript, we use a `Map` and `Array` objects to implement the algorithm.

## A solution in C++

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

int minJumps(std::vector<int>& arr) {
    int n = arr.size();
    if (n <= 1) return 0;

    std::unordered_map<int, std::vector<int>> value_indices;
    for (int i = 0; i < n; ++i) {
        value_indices[arr[i]].push_back(i);
    }

    std::queue<int> q;
    std::vector<bool> visited(n, false);

    q.push(0);
    visited[0] = true;
    int steps = 0;

    while (!q.empty()) {
        int size = q.size();

        for (int i = 0; i < size; ++i) {
            int index = q.front();
            q.pop();

            if (index == n - 1) return steps;

            if (index > 0 && !visited[index - 1]) {
                q.push(index - 1);
                visited[index - 1] = true;
            }

            if (index < n - 1 && !visited[index + 1]) {
                q.push(index + 1);
                visited[index + 1] = true;
            }

            for (int neighbor : value_indices[arr[index]]) {
                if (!visited[neighbor]) {
                    q.push(neighbor);
                    visited[neighbor] = true;
                }
            }

            value_indices[arr[index]].clear();
        }

        ++steps;
    }

    return -1;
}
```
The algorithm to solve this problem is using the Breadth-First Search (BFS) approach.

1. First, iterate through the `arr` and create a hash map (`value_indices`) to map each unique value to their indices in the array.
2. Initialize the BFS queue `q`, the visited array `visited`, and steps counter `steps`.
3. While queue `q` is not empty, perform the following:
   a. Set the `size` variable as the current length of the queue `q`.
   b. Iterate through the `size` of the queue `q`. For each iteration:
      i. Pop the front of the queue `q` and assign the popped index to `index`.
      ii. If the popped index is the last index of the array, return the steps counter.
      iii. Check the valid neighbors `(index-1, index+1, or the same value as arr[index])` that haven't been visited yet:
         - If it's a valid neighbor and not visited before, mark the neighbor as visited and push the neighbor to the queue `q`.
      iv. Clear the value_indices entry for this index, as we don't want to revisit it.
   c. Increase the steps counter by 1.
4. If the last index is not reached, return -1. (This will not happen in the given constraints)

In each programming language, the major difference is in the syntax and data structures used to implement this algorithm. The key points of the language-specific implementations are as follows:

- In C++, we use `std::vector`, `std::queue`, `std::unordered_map`, and `std::vector<bool>` for array manipulation and storage.
- In Java, we use `java.util.HashMap`, `java.util.LinkedList` for both queue and mapping values, and a boolean array for storing visited status.
- In Python, we use Python's `list` and `collections.defaultdict` for mapping values and storing visited status.
- In JavaScript, we use a `Map` and `Array` objects to implement the algorithm.

## A solution in Python

```python
from collections import defaultdict

def minJumps(arr):
    n = len(arr)
    if n <= 1:
        return 0

    value_indices = defaultdict(list)

    for i, value in enumerate(arr):
        value_indices[value].append(i)

    q = [0]
    visited = [False] * n
    visited[0] = True
    steps = 0

    while q:
        size = len(q)
        for _ in range(size):
            index = q.pop(0)

            if index == n - 1:
                return steps

            if index > 0 and not visited[index - 1]:
                q.append(index - 1)
                visited[index - 1] = True

            if index < n - 1 and not visited[index + 1]:
                q.append(index + 1)
                visited[index + 1] = True

            for neighbor in value_indices[arr[index]]:
                if not visited[neighbor]:
                    q.append(neighbor)
                    visited[neighbor] = True

            value_indices[arr[index]] = []

        steps += 1

    return -1
```
The algorithm to solve this problem is using the Breadth-First Search (BFS) approach.

1. First, iterate through the `arr` and create a hash map (`value_indices`) to map each unique value to their indices in the array.
2. Initialize the BFS queue `q`, the visited array `visited`, and steps counter `steps`.
3. While queue `q` is not empty, perform the following:
   a. Set the `size` variable as the current length of the queue `q`.
   b. Iterate through the `size` of the queue `q`. For each iteration:
      i. Pop the front of the queue `q` and assign the popped index to `index`.
      ii. If the popped index is the last index of the array, return the steps counter.
      iii. Check the valid neighbors `(index-1, index+1, or the same value as arr[index])` that haven't been visited yet:
         - If it's a valid neighbor and not visited before, mark the neighbor as visited and push the neighbor to the queue `q`.
      iv. Clear the value_indices entry for this index, as we don't want to revisit it.
   c. Increase the steps counter by 1.
4. If the last index is not reached, return -1. (This will not happen in the given constraints)

In each programming language, the major difference is in the syntax and data structures used to implement this algorithm. The key points of the language-specific implementations are as follows:

- In C++, we use `std::vector`, `std::queue`, `std::unordered_map`, and `std::vector<bool>` for array manipulation and storage.
- In Java, we use `java.util.HashMap`, `java.util.LinkedList` for both queue and mapping values, and a boolean array for storing visited status.
- In Python, we use Python's `list` and `collections.defaultdict` for mapping values and storing visited status.
- In JavaScript, we use a `Map` and `Array` objects to implement the algorithm.

## A solution in Javascript

```javascript
/**
 * @param {number[]} arr
 * @return {number}
 */
function minJumps(arr) {
  const n = arr.length;
  if (n <= 1) return 0;

  const valueIndices = new Map();

  for (let i = 0; i < n; ++i) {
    if (!valueIndices.has(arr[i])) valueIndices.set(arr[i], []);
    valueIndices.get(arr[i]).push(i);
  }

  const q = [0];
  const visited = new Array(n).fill(false);
  visited[0] = true;
  let steps = 0;

  while (q.length) {
    const size = q.length;

    for (let i = 0; i < size; ++i) {
      const index = q.shift();

      if (index === n - 1) return steps;

      if (index > 0 && !visited[index - 1]) {
        q.push(index - 1);
        visited[index - 1] = true;
      }

      if (index < n - 1 && !visited[index + 1]) {
        q.push(index + 1);
        visited[index + 1] = true;
      }

      for (const neighbor of valueIndices.get(arr[index])) {
        if (!visited[neighbor]) {
          q.push(neighbor);
          visited[neighbor] = true;
        }
      }

      valueIndices.set(arr[index], []);
    }

    ++steps;
  }

  return -1;
}
```
The algorithm to solve this problem is using the Breadth-First Search (BFS) approach.

1. First, iterate through the `arr` and create a hash map (`value_indices`) to map each unique value to their indices in the array.
2. Initialize the BFS queue `q`, the visited array `visited`, and steps counter `steps`.
3. While queue `q` is not empty, perform the following:
   a. Set the `size` variable as the current length of the queue `q`.
   b. Iterate through the `size` of the queue `q`. For each iteration:
      i. Pop the front of the queue `q` and assign the popped index to `index`.
      ii. If the popped index is the last index of the array, return the steps counter.
      iii. Check the valid neighbors `(index-1, index+1, or the same value as arr[index])` that haven't been visited yet:
         - If it's a valid neighbor and not visited before, mark the neighbor as visited and push the neighbor to the queue `q`.
      iv. Clear the value_indices entry for this index, as we don't want to revisit it.
   c. Increase the steps counter by 1.
4. If the last index is not reached, return -1. (This will not happen in the given constraints)

In each programming language, the major difference is in the syntax and data structures used to implement this algorithm. The key points of the language-specific implementations are as follows:

- In C++, we use `std::vector`, `std::queue`, `std::unordered_map`, and `std::vector<bool>` for array manipulation and storage.
- In Java, we use `java.util.HashMap`, `java.util.LinkedList` for both queue and mapping values, and a boolean array for storing visited status.
- In Python, we use Python's `list` and `collections.defaultdict` for mapping values and storing visited status.
- In JavaScript, we use a `Map` and `Array` objects to implement the algorithm.


# Check If N and Its Double Exist

- slug: check-if-n-and-its-double-exist
- difficulty: Easy

Given an array `arr` of integers, check if there exist two indices `i` and `j` such that :

*   `i != j`
*   `0 <= i, j < arr.length`
*   `arr[i] == 2 * arr[j]`

**Example 1:**

**Input:** arr = \[10,2,5,3\]
**Output:** true
**Explanation:** For i = 0 and j = 2, arr\[i\] == 10 == 2 \* 5 == 2 \* arr\[j\]

**Example 2:**

**Input:** arr = \[3,1,7,11\]
**Output:** false
**Explanation:** There is no i and j that satisfy the conditions.

**Constraints:**

*   `2 <= arr.length <= 500`
*   `-103 <= arr[i] <= 103`

## A solution in Java

```java
public int maxValueInStack(int[] nums, int k) {
    int n = nums.length;
    if (k >= n) return -1;

    int max_val = Integer.MIN_VALUE;
    for (int i = 0; i <= k; ++i) {
        max_val = Math.max(max_val, nums[i]);
    }
    return max_val;
}
```
We are looking for the maximum `nums[i]` such that `0 <= i <= k`. Iterate through the first `k+1` elements in the array and keep track of the maximum value encountered. If `k >= n`, then it's not possible to have a non-empty pile after k moves, so return `-1` in that case. Otherwise, return the maximum value found.

## A solution in C++

```cpp
int maxValueInStack(vector<int>& nums, int k) {
    int n = nums.size();
    if (k >= n) return -1;

    int max_val = INT_MIN;
    for (int i = 0; i <= k; ++i) {
        max_val = max(max_val, nums[i]);
    }
    return max_val;
}
```
We are looking for the maximum `nums[i]` such that `0 <= i <= k`. Iterate through the first `k+1` elements in the array and keep track of the maximum value encountered. If `k >= n`, then it's not possible to have a non-empty pile after k moves, so return `-1` in that case. Otherwise, return the maximum value found.

## A solution in Python

```python
def maxValueInStack(nums, k):
    n = len(nums)
    if k >= n:
        return -1

    max_val = float('-inf')
    for i in range(k+1):
        max_val = max(max_val, nums[i])
    return max_val
```
We are looking for the maximum `nums[i]` such that `0 <= i <= k`. Iterate through the first `k+1` elements in the array and keep track of the maximum value encountered. If `k >= n`, then it's not possible to have a non-empty pile after k moves, so return `-1` in that case. Otherwise, return the maximum value found.

## A solution in Javascript

```javascript
function maxValueInStack(nums, k) {
    let n = nums.length;
    if (k >= n) return -1;

    let max_val = Number.MIN_SAFE_INTEGER;
    for (let i = 0; i <= k; ++i) {
        max_val = Math.max(max_val, nums[i]);
    }
    return max_val;
}
```
We are looking for the maximum `nums[i]` such that `0 <= i <= k`. Iterate through the first `k+1` elements in the array and keep track of the maximum value encountered. If `k >= n`, then it's not possible to have a non-empty pile after k moves, so return `-1` in that case. Otherwise, return the maximum value found.


# Minimum Number of Steps to Make Two Strings Anagram

- slug: minimum-number-of-steps-to-make-two-strings-anagram
- difficulty: Medium

You are given two strings of the same length `s` and `t`. In one step you can choose **any character** of `t` and replace it with **another character**.

Return _the minimum number of steps_ to make `t` an anagram of `s`.

An **Anagram** of a string is a string that contains the same characters with a different (or the same) ordering.

**Example 1:**

**Input:** s =  "bab ", t =  "aba "
**Output:** 1
**Explanation:** Replace the first 'a' in t with b, t =  "bba " which is anagram of s.

**Example 2:**

**Input:** s =  "leetcode ", t =  "practice "
**Output:** 5
**Explanation:** Replace 'p', 'r', 'a', 'i' and 'c' from t with proper characters to make t anagram of s.

**Example 3:**

**Input:** s =  "anagram ", t =  "mangaar "
**Output:** 0
**Explanation:**  "anagram " and  "mangaar " are anagrams.

**Constraints:**

*   `1 <= s.length <= 5 * 104`
*   `s.length == t.length`
*   `s` and `t` consist of lowercase English letters only.

## A solution in Java

```java
public int minSteps(String s, String t) {
    int[] s_Count = new int[26];
    int[] t_Count = new int[26];
    for(char c : s.toCharArray()) s_Count[c - 'a']++;
    for(char c : t.toCharArray()) t_Count[c - 'a']++;
    int res = 0;
    for(int i = 0; i < 26; i++) {
        res += Math.abs(s_Count[i] - t_Count[i]);
    }
    return res / 2;
}
```
1. Initialize two arrays, `s_Count` and `t_Count`, of length 26, both filled with zeros. These arrays will represent the character counts in strings `s` and `t`. The index represents the respective character number and the value at that index represents the count of the character.
2. Iterate through both strings `s` and `t` and increase the count of characters in their respective count arrays.
3. Initialize a counter `res` to zero.
4. Iterate through the arrays `s_Count` and `t_Count` and calculate the absolute difference between the counts for each character. Add the difference to the counter variable `res`.
5. Return half of the `res` variable (since we counted the difference two times, i.e., in both `s` and `t`).

This algorithm has a time complexity of O(n) since we iterate through both strings once and the count arrays once.

## A solution in C++

```cpp
int minSteps(string s, string t) {
    vector<int> s_Count(26, 0);
    vector<int> t_Count(26, 0);
    for(char c : s) s_Count[c - 'a']++;
    for(char c : t) t_Count[c - 'a']++;
    int res = 0;
    for(int i = 0; i < 26; i++) {
        res += abs(s_Count[i] - t_Count[i]);
    }
    return res / 2;
}
```
1. Initialize two arrays, `s_Count` and `t_Count`, of length 26, both filled with zeros. These arrays will represent the character counts in strings `s` and `t`. The index represents the respective character number and the value at that index represents the count of the character.
2. Iterate through both strings `s` and `t` and increase the count of characters in their respective count arrays.
3. Initialize a counter `res` to zero.
4. Iterate through the arrays `s_Count` and `t_Count` and calculate the absolute difference between the counts for each character. Add the difference to the counter variable `res`.
5. Return half of the `res` variable (since we counted the difference two times, i.e., in both `s` and `t`).

This algorithm has a time complexity of O(n) since we iterate through both strings once and the count arrays once.

## A solution in Python

```python
def minSteps(s, t):
    s_Count = [0] * 26
    t_Count = [0] * 26
    for c in s: s_Count[ord(c) - ord('a')] += 1
    for c in t: t_Count[ord(c) - ord('a')] += 1
    res = 0
    for i in range(26):
        res += abs(s_Count[i] - t_Count[i])
    return res // 2
```
1. Initialize two arrays, `s_Count` and `t_Count`, of length 26, both filled with zeros. These arrays will represent the character counts in strings `s` and `t`. The index represents the respective character number and the value at that index represents the count of the character.
2. Iterate through both strings `s` and `t` and increase the count of characters in their respective count arrays.
3. Initialize a counter `res` to zero.
4. Iterate through the arrays `s_Count` and `t_Count` and calculate the absolute difference between the counts for each character. Add the difference to the counter variable `res`.
5. Return half of the `res` variable (since we counted the difference two times, i.e., in both `s` and `t`).

This algorithm has a time complexity of O(n) since we iterate through both strings once and the count arrays once.

## A solution in Javascript

```javascript
function minSteps(s, t) {
    const s_Count = new Array(26).fill(0);
    const t_Count = new Array(26).fill(0);
    for(let c of s) s_Count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
    for(let c of t) t_Count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++;
    let res = 0;
    for(let i = 0; i < 26; i++) {
        res += Math.abs(s_Count[i] - t_Count[i]);
    }
    return res / 2;
}
```
1. Initialize two arrays, `s_Count` and `t_Count`, of length 26, both filled with zeros. These arrays will represent the character counts in strings `s` and `t`. The index represents the respective character number and the value at that index represents the count of the character.
2. Iterate through both strings `s` and `t` and increase the count of characters in their respective count arrays.
3. Initialize a counter `res` to zero.
4. Iterate through the arrays `s_Count` and `t_Count` and calculate the absolute difference between the counts for each character. Add the difference to the counter variable `res`.
5. Return half of the `res` variable (since we counted the difference two times, i.e., in both `s` and `t`).

This algorithm has a time complexity of O(n) since we iterate through both strings once and the count arrays once.


# Tweet Counts Per Frequency

- slug: tweet-counts-per-frequency
- difficulty: Medium

A social media company is trying to monitor activity on their site by analyzing the number of tweets that occur in select periods of time. These periods can be partitioned into smaller **time chunks** based on a certain frequency (every **minute**, **hour**, or **day**).

For example, the period `[10, 10000]` (in **seconds**) would be partitioned into the following **time chunks** with these frequencies:

*   Every **minute** (60-second chunks): `[10,69]`, `[70,129]`, `[130,189]`, `...`, `[9970,10000]`
*   Every **hour** (3600-second chunks): `[10,3609]`, `[3610,7209]`, `[7210,10000]`
*   Every **day** (86400-second chunks): `[10,10000]`

Notice that the last chunk may be shorter than the specified frequency's chunk size and will always end with the end time of the period (`10000` in the above example).

Design and implement an API to help the company with their analysis.

Implement the `TweetCounts` class:

*   `TweetCounts()` Initializes the `TweetCounts` object.
*   `void recordTweet(String tweetName, int time)` Stores the `tweetName` at the recorded `time` (in **seconds**).
*   `List getTweetCountsPerFrequency(String freq, String tweetName, int startTime, int endTime)` Returns a list of integers representing the number of tweets with `tweetName` in each **time chunk** for the given period of time `[startTime, endTime]` (in **seconds**) and frequency `freq`.
    *   `freq` is one of `"minute "`, `"hour "`, or `"day "` representing a frequency of every **minute**, **hour**, or **day** respectively.

**Example:**

**Input**
\[ "TweetCounts ", "recordTweet ", "recordTweet ", "recordTweet ", "getTweetCountsPerFrequency ", "getTweetCountsPerFrequency ", "recordTweet ", "getTweetCountsPerFrequency "\]
\[\[\],\[ "tweet3 ",0\],\[ "tweet3 ",60\],\[ "tweet3 ",10\],\[ "minute ", "tweet3 ",0,59\],\[ "minute ", "tweet3 ",0,60\],\[ "tweet3 ",120\],\[ "hour ", "tweet3 ",0,210\]\]

**Output**
\[null,null,null,null,\[2\],\[2,1\],null,\[4\]\]

**Explanation**
TweetCounts tweetCounts = new TweetCounts();
tweetCounts.recordTweet( "tweet3 ", 0);                              // New tweet  "tweet3 " at time 0
tweetCounts.recordTweet( "tweet3 ", 60);                             // New tweet  "tweet3 " at time 60
tweetCounts.recordTweet( "tweet3 ", 10);                             // New tweet  "tweet3 " at time 10
tweetCounts.getTweetCountsPerFrequency( "minute ",  "tweet3 ", 0, 59); // return \[2\]; chunk \[0,59\] had 2 tweets
tweetCounts.getTweetCountsPerFrequency( "minute ",  "tweet3 ", 0, 60); // return \[2,1\]; chunk \[0,59\] had 2 tweets, chunk \[60,60\] had 1 tweet
tweetCounts.recordTweet( "tweet3 ", 120);                            // New tweet  "tweet3 " at time 120
tweetCounts.getTweetCountsPerFrequency( "hour ",  "tweet3 ", 0, 210);  // return \[4\]; chunk \[0,210\] had 4 tweets

**Constraints:**

*   `0 <= time, startTime, endTime <= 109`
*   `0 <= endTime - startTime <= 104`
*   There will be at most `104` calls **in total** to `recordTweet` and `getTweetCountsPerFrequency`.

## A solution in Java

```java
import java.util.*;

class TweetCounts {

    private Map<String, TreeMap<Integer, Integer>> data;

    public TweetCounts() {
        data = new HashMap<>();
    }

    public void recordTweet(String tweetName, int time) {
        if (!data.containsKey(tweetName)) {
            data.put(tweetName, new TreeMap<>());
        }
        data.get(tweetName).put(time, data.get(tweetName).getOrDefault(time, 0) + 1);
    }

    public List<Integer> getTweetCountsPerFrequency(String freq, String tweetName, int startTime, int endTime) {
        int step = freq.equals("minute") ? 60 : freq.equals("hour") ? 3600 : 86400;
        List<Integer> chunks = new ArrayList<>(Collections.nCopies((endTime - startTime) / step + 1, 0));

        if (data.containsKey(tweetName)) {
            for (Map.Entry<Integer, Integer> entry : data.get(tweetName).subMap(startTime, true, endTime, true).entrySet()) {
                int chunk_index = (entry.getKey() - startTime) / step;
                if (chunk_index >= 0 && chunk_index < chunks.size()) {
                    chunks.set(chunk_index, chunks.get(chunk_index) + entry.getValue());
                }
            }
        }

        return chunks;
    }
}
```
The algorithm uses a HashMap or Dictionary (depending on the language), with the key being the tweet name and the value being a TreeMap, where the key of this TreeMap is the timestamp and the value is the count of tweets at that timestamp.

When recording a tweet, simply update the count for the timestamp in the TreeMap of the specific tweet name.

When querying the number of tweet counts per frequency, first determine the step size based on the frequency, whether it's 60 for minutes, 3600 for hours, or 86400 for days. Then initialize an array of desired length to store tweet count for each chunk.

Iterate through the TreeMap, for each timestamp that falls in [startTime, endTime], increment the corresponding time chunk's count. Finally, return the array of counts.

Note: As specified, the algorithm would be called at most 1e4 times in total, so this solution is efficient enough. However, if a better performance is required, the TreeMap can be replaced with an advanced data structure like an interval tree which allows faster range queries.

## A solution in C++

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

using namespace std;

class TweetCounts {
public:
    TweetCounts() {}

    void recordTweet(string tweetName, int time) {
        data[tweetName][time]++;
    }

    vector<int> getTweetCountsPerFrequency(string freq, string tweetName, int startTime, int endTime) {
        int step = (freq == "minute") ? 60 : (freq == "hour") ? 3600 : 86400;
        vector<int> chunks((endTime - startTime) / step + 1, 0);

        if (data.count(tweetName)) {
            for (auto kvp : data[tweetName]) {
                int chunk_index = (kvp.first - startTime) / step;
                if (chunk_index >= 0 && chunk_index < chunks.size()) {
                    chunks[chunk_index] += kvp.second;
                }
            }
        }

        return chunks;
    }

private:
    unordered_map<string, map<int, int>> data;
};
```
The algorithm uses a HashMap or Dictionary (depending on the language), with the key being the tweet name and the value being a TreeMap, where the key of this TreeMap is the timestamp and the value is the count of tweets at that timestamp.

When recording a tweet, simply update the count for the timestamp in the TreeMap of the specific tweet name.

When querying the number of tweet counts per frequency, first determine the step size based on the frequency, whether it's 60 for minutes, 3600 for hours, or 86400 for days. Then initialize an array of desired length to store tweet count for each chunk.

Iterate through the TreeMap, for each timestamp that falls in [startTime, endTime], increment the corresponding time chunk's count. Finally, return the array of counts.

Note: As specified, the algorithm would be called at most 1e4 times in total, so this solution is efficient enough. However, if a better performance is required, the TreeMap can be replaced with an advanced data structure like an interval tree which allows faster range queries.

## A solution in Python

```python
from collections import defaultdict
from typing import List

class TweetCounts:

    def __init__(self):
        self.data = defaultdict(dict)

    def recordTweet(self, tweetName: str, time: int) -> None:
        if time not in self.data[tweetName]:
            self.data[tweetName][time] = 1
        else:
            self.data[tweetName][time] += 1

    def getTweetCountsPerFrequency(self, freq: str, tweetName: str, startTime: int, endTime: int) -> List[int]:
        step = 60 if freq == "minute" else 3600 if freq == "hour" else 86400
        chunks = [0] * ((endTime - startTime) // step + 1)

        if tweetName in self.data:
            for time, count in self.data[tweetName].items():
                chunk_index = (time - startTime) // step
                if 0 <= chunk_index < len(chunks):
                    chunks[chunk_index] += count

        return chunks
```
The algorithm uses a HashMap or Dictionary (depending on the language), with the key being the tweet name and the value being a TreeMap, where the key of this TreeMap is the timestamp and the value is the count of tweets at that timestamp.

When recording a tweet, simply update the count for the timestamp in the TreeMap of the specific tweet name.

When querying the number of tweet counts per frequency, first determine the step size based on the frequency, whether it's 60 for minutes, 3600 for hours, or 86400 for days. Then initialize an array of desired length to store tweet count for each chunk.

Iterate through the TreeMap, for each timestamp that falls in [startTime, endTime], increment the corresponding time chunk's count. Finally, return the array of counts.

Note: As specified, the algorithm would be called at most 1e4 times in total, so this solution is efficient enough. However, if a better performance is required, the TreeMap can be replaced with an advanced data structure like an interval tree which allows faster range queries.

## A solution in Javascript

```javascript
class TweetCounts {
    constructor() {
        this.data = new Map();
    }

    recordTweet(tweetName, time) {
        if (!this.data.has(tweetName)) {
            this.data.set(tweetName, new Map());
        }
        const times = this.data.get(tweetName);
        times.set(time, (times.get(time) || 0) + 1);
    }

    getTweetCountsPerFrequency(freq, tweetName, startTime, endTime) {
        const step = freq === "minute" ? 60 : freq === "hour" ? 3600 : 86400;
        const chunks = new Array(Math.floor((endTime - startTime) / step) + 1).fill(0);

        if (this.data.has(tweetName)) {
            for (const [time, count] of this.data.get(tweetName)) {
                const chunkIndex = Math.floor((time - startTime) / step);
                if (chunkIndex >= 0 && chunkIndex < chunks.length) {
                    chunks[chunkIndex] += count;
                }
            }
        }

        return chunks;
    }
}
```
The algorithm uses a HashMap or Dictionary (depending on the language), with the key being the tweet name and the value being a TreeMap, where the key of this TreeMap is the timestamp and the value is the count of tweets at that timestamp.

When recording a tweet, simply update the count for the timestamp in the TreeMap of the specific tweet name.

When querying the number of tweet counts per frequency, first determine the step size based on the frequency, whether it's 60 for minutes, 3600 for hours, or 86400 for days. Then initialize an array of desired length to store tweet count for each chunk.

Iterate through the TreeMap, for each timestamp that falls in [startTime, endTime], increment the corresponding time chunk's count. Finally, return the array of counts.

Note: As specified, the algorithm would be called at most 1e4 times in total, so this solution is efficient enough. However, if a better performance is required, the TreeMap can be replaced with an advanced data structure like an interval tree which allows faster range queries.


# Maximum Students Taking Exam

- slug: maximum-students-taking-exam
- difficulty: Hard

Given a `m * n` matrix `seats` that represent seats distributions in a classroom. If a seat is broken, it is denoted by `'#'` character otherwise it is denoted by a `'.'` character.

Students can see the answers of those sitting next to the left, right, upper left and upper right, but he cannot see the answers of the student sitting directly in front or behind him. Return the **maximum** number of students that can take the exam together without any cheating being possible..

Students must be placed in seats in good condition.

**Example 1:**

**Input:** seats = \[\[ "# ", ". ", "# ", "# ", ". ", "# "\],
                \[ ". ", "# ", "# ", "# ", "# ", ". "\],
                \[ "# ", ". ", "# ", "# ", ". ", "# "\]\]
**Output:** 4
**Explanation:** Teacher can place 4 students in available seats so they don't cheat on the exam.

**Example 2:**

**Input:** seats = \[\[ ". ", "# "\],
                \[ "# ", "# "\],
                \[ "# ", ". "\],
                \[ "# ", "# "\],
                \[ ". ", "# "\]\]
**Output:** 3
**Explanation:** Place all students in available seats.

**Example 3:**

**Input:** seats = \[\[ "# ", ". ", "**.** ", ". ", "# "\],
                \[ "**.** ", "# ", "**.** ", "# ", "**.** "\],
                \[ "**.** ", ". ", "# ", ". ", "**.** "\],
                \[ "**.** ", "# ", "**.** ", "# ", "**.** "\],
                \[ "# ", ". ", "**.** ", ". ", "# "\]\]
**Output:** 10
**Explanation:** Place students in available seats in column 1, 3 and 5.

**Constraints:**

*   `seats` contains only characters `'.' and``'#'.`
*   `m == seats.length`
*   `n == seats[i].length`
*   `1 <= m <= 8`
*   `1 <= n <= 8`

## A solution in Java

```java
class Solution {
    public boolean checkStraightLine(int[][] coordinates) {
        int dx = coordinates[1][0] - coordinates[0][0];
        int dy = coordinates[1][1] - coordinates[0][1];

        for(int i = 2; i < coordinates.length; i++) {
            int x = coordinates[i][0] - coordinates[0][0];
            int y = coordinates[i][1] - coordinates[0][1];
            if(dx * y != dy * x) return false;
        }

        return true;
    }
}
```
The algorithm checks if the given points make a straight line in the XY plane. It calculates the slope (delta y / delta x) between the first two points in the array, and then iterates through the rest of the points comparing their slopes against the calculated slope. This is done by checking if `(dx * y) == (dy * x)` for each point. If any point has a different slope, return false (meaning the points don't make a straight line). If all points have the same slope, return true (meaning the points make a straight line).

## A solution in C++

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

bool checkStraightLine(vector<vector<int>>& coordinates) {
    int dx = coordinates[1][0] - coordinates[0][0];
    int dy = coordinates[1][1] - coordinates[0][1];

    for(int i = 2; i < coordinates.size(); ++i) {
        int x = coordinates[i][0] - coordinates[0][0];
        int y = coordinates[i][1] - coordinates[0][1];
        if(dx * y != dy * x) return false;
    }

    return true;
}
```
The algorithm checks if the given points make a straight line in the XY plane. It calculates the slope (delta y / delta x) between the first two points in the array, and then iterates through the rest of the points comparing their slopes against the calculated slope. This is done by checking if `(dx * y) == (dy * x)` for each point. If any point has a different slope, return false (meaning the points don't make a straight line). If all points have the same slope, return true (meaning the points make a straight line).

## A solution in Python

```python
from typing import List

def checkStraightLine(coordinates: List[List[int]]) -> bool:
    dx = coordinates[1][0] - coordinates[0][0]
    dy = coordinates[1][1] - coordinates[0][1]

    for x, y in coordinates[2:]:
        if dx * (y - coordinates[0][1]) != dy * (x - coordinates[0][0]):
            return False

    return True
```
The algorithm checks if the given points make a straight line in the XY plane. It calculates the slope (delta y / delta x) between the first two points in the array, and then iterates through the rest of the points comparing their slopes against the calculated slope. This is done by checking if `(dx * y) == (dy * x)` for each point. If any point has a different slope, return false (meaning the points don't make a straight line). If all points have the same slope, return true (meaning the points make a straight line).

## A solution in Javascript

```javascript
var checkStraightLine = function(coordinates) {
    let dx = coordinates[1][0] - coordinates[0][0];
    let dy = coordinates[1][1] - coordinates[0][1];

    for(let i = 2; i < coordinates.length; i++) {
        let x = coordinates[i][0] - coordinates[0][0];
        let y = coordinates[i][1] - coordinates[0][1];
        if(dx * y != dy * x) return false;
    }

    return true;
};
```
The algorithm checks if the given points make a straight line in the XY plane. It calculates the slope (delta y / delta x) between the first two points in the array, and then iterates through the rest of the points comparing their slopes against the calculated slope. This is done by checking if `(dx * y) == (dy * x)` for each point. If any point has a different slope, return false (meaning the points don't make a straight line). If all points have the same slope, return true (meaning the points make a straight line).


# Count Negative Numbers in a Sorted Matrix

- slug: count-negative-numbers-in-a-sorted-matrix
- difficulty: Easy

Given a `m x n` matrix `grid` which is sorted in non-increasing order both row-wise and column-wise, return _the number of **negative** numbers in_ `grid`.

**Example 1:**

**Input:** grid = \[\[4,3,2,-1\],\[3,2,1,-1\],\[1,1,-1,-2\],\[-1,-1,-2,-3\]\]
**Output:** 8
**Explanation:** There are 8 negatives number in the matrix.

**Example 2:**

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

**Constraints:**

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

**Follow up:** Could you find an `O(n + m)` solution?

## A solution in Java

```java
import java.util.HashMap;

public int balancedString(String s) {
    int n = s.length();
    HashMap<Character, Integer> freq_map = new HashMap<>();
    for (char c : s.toCharArray())
        freq_map.put(c, freq_map.getOrDefault(c, 0) + 1);

    int i = 0, result = n;
    for (int j = 0; j < n; j++) {
        freq_map.put(s.charAt(j), freq_map.get(s.charAt(j)) - 1);
        while (i < n && freq_map.getOrDefault('Q', 0) <= n / 4 && freq_map.getOrDefault('W', 0) <= n / 4 && freq_map.getOrDefault('E', 0) <= n / 4 && freq_map.getOrDefault('R', 0) <= n / 4) {
            result = Math.min(result, j - i + 1);
            freq_map.put(s.charAt(i), freq_map.get(s.charAt(i)) + 1);
            i++;
        }
    }
    return result;
}
```
1. Create a frequency map of characters in the given string.
2. Initialize two pointers, i and j, to traverse the string.
3. Traverse the string with pointer j and decrease the frequency of the current character.
4. Check if the frequency of all characters is less than or equal to n/4. If so, update the minimum length of substring.
5. Increment pointer i while maintaining the frequency map until the frequency of any character becomes more than n/4.
6. Return the minimum length of substring found.

## A solution in C++

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

int balancedString(string s) {
    int n = s.size();
    unordered_map<char, int> freq_map;
    for (char c : s)
        freq_map[c]++;

    int i = 0, result = n;
    for (int j = 0; j < n; j++) {
        freq_map[s[j]]--;
        while (i < n && freq_map['Q'] <= n / 4 && freq_map['W'] <= n / 4 && freq_map['E'] <= n / 4 && freq_map['R'] <= n / 4) {
            result = min(result, j - i + 1);
            freq_map[s[i]]++;
            i++;
        }
    }
    return result;
}
```
1. Create a frequency map of characters in the given string.
2. Initialize two pointers, i and j, to traverse the string.
3. Traverse the string with pointer j and decrease the frequency of the current character.
4. Check if the frequency of all characters is less than or equal to n/4. If so, update the minimum length of substring.
5. Increment pointer i while maintaining the frequency map until the frequency of any character becomes more than n/4.
6. Return the minimum length of substring found.

## A solution in Python

```python
def balanced_string(s):
    n = len(s)
    freq_map = {}
    for c in s:
        freq_map[c] = freq_map.get(c, 0) + 1

    i = 0
    result = n
    for j in range(n):
        freq_map[s[j]] -= 1
        while i < n and all(freq_map.get(c, 0) <= n // 4 for c in "QWER"):
            result = min(result, j - i + 1)
            freq_map[s[i]] += 1
            i += 1

    return result
```
1. Create a frequency map of characters in the given string.
2. Initialize two pointers, i and j, to traverse the string.
3. Traverse the string with pointer j and decrease the frequency of the current character.
4. Check if the frequency of all characters is less than or equal to n/4. If so, update the minimum length of substring.
5. Increment pointer i while maintaining the frequency map until the frequency of any character becomes more than n/4.
6. Return the minimum length of substring found.

## A solution in Javascript

```javascript
function balancedString(s) {
    const n = s.length;
    const freq_map = {};
    for (const c of s)
        freq_map[c] = (freq_map[c] || 0) + 1;

    let i = 0, result = n;
    for (let j = 0; j < n; j++) {
        freq_map[s[j]]--;
        while (i < n && ['Q', 'W', 'E', 'R'].every(c => (freq_map[c] || 0) <= n / 4)) {
            result = Math.min(result, j - i + 1);
            freq_map[s[i]]++;
            i++;
        }
    }
    return result;
}
```
1. Create a frequency map of characters in the given string.
2. Initialize two pointers, i and j, to traverse the string.
3. Traverse the string with pointer j and decrease the frequency of the current character.
4. Check if the frequency of all characters is less than or equal to n/4. If so, update the minimum length of substring.
5. Increment pointer i while maintaining the frequency map until the frequency of any character becomes more than n/4.
6. Return the minimum length of substring found.


# Product of the Last K Numbers

- slug: product-of-the-last-k-numbers
- difficulty: Medium

Design an algorithm that accepts a stream of integers and retrieves the product of the last `k` integers of the stream.

Implement the `ProductOfNumbers` class:

*   `ProductOfNumbers()` Initializes the object with an empty stream.
*   `void add(int num)` Appends the integer `num` to the stream.
*   `int getProduct(int k)` Returns the product of the last `k` numbers in the current list. You can assume that always the current list has at least `k` numbers.

The test cases are generated so that, at any time, the product of any contiguous sequence of numbers will fit into a single 32-bit integer without overflowing.

**Example:**

**Input**
\[ "ProductOfNumbers ", "add ", "add ", "add ", "add ", "add ", "getProduct ", "getProduct ", "getProduct ", "add ", "getProduct "\]
\[\[\],\[3\],\[0\],\[2\],\[5\],\[4\],\[2\],\[3\],\[4\],\[8\],\[2\]\]

**Output**
\[null,null,null,null,null,null,20,40,0,null,32\]

**Explanation**
ProductOfNumbers productOfNumbers = new ProductOfNumbers();
productOfNumbers.add(3);        // \[3\]
productOfNumbers.add(0);        // \[3,0\]
productOfNumbers.add(2);        // \[3,0,2\]
productOfNumbers.add(5);        // \[3,0,2,5\]
productOfNumbers.add(4);        // \[3,0,2,5,4\]
productOfNumbers.getProduct(2); // return 20. The product of the last 2 numbers is 5 \* 4 = 20
productOfNumbers.getProduct(3); // return 40. The product of the last 3 numbers is 2 \* 5 \* 4 = 40
productOfNumbers.getProduct(4); // return 0. The product of the last 4 numbers is 0 \* 2 \* 5 \* 4 = 0
productOfNumbers.add(8);        // \[3,0,2,5,4,8\]
productOfNumbers.getProduct(2); // return 32. The product of the last 2 numbers is 4 \* 8 = 32

**Constraints:**

*   `0 <= num <= 100`
*   `1 <= k <= 4 * 104`
*   At most `4 * 104` calls will be made to `add` and `getProduct`.
*   The product of the stream at any point in time will fit in a **32-bit** integer.

## A solution in Java

```java
import java.util.Arrays;

class Job {
    int start;
    int end;
    int profit;

    public Job(int start, int end, int profit) {
        this.start = start;
        this.end = end;
        this.profit = profit;
    }
}

public int maxProfit(int[] startTime, int[] endTime, int[] profit) {
    int n = startTime.length;
    Job[] jobs = new Job[n];

    for (int i = 0; i < n; i++) {
        jobs[i] = new Job(startTime[i], endTime[i], profit[i]);
    }

    Arrays.sort(jobs, (a, b) -> a.end - b.end);

    int[] memo = new int[n];
    Arrays.fill(memo, -1);
    return maxProfitHelper(jobs, memo, n - 1);
}

private int findNextJob(Job[] jobs, int i) {
    for (int j = i + 1; j < jobs.length; j++) {
        if (jobs[j].start >= jobs[i].end) {
            return j;
        }
    }
    return -1;
}

private int maxProfitHelper(Job[] jobs, int[] memo, int i) {
    if (i == -1) return 0;
    if (memo[i] != -1) return memo[i];

    int nextJob = findNextJob(jobs, i);
    int inclCurrJob = jobs[i].profit + maxProfitHelper(jobs, memo, nextJob);
    int exclCurrJob = maxProfitHelper(jobs, memo, i - 1);

    memo[i] = Math.max(inclCurrJob, exclCurrJob);
    return memo[i];
}
```
The algorithm uses dynamic programming with memoization to find the maximum profit:

1. Define a `Job` class or struct with `start`, `end`, and `profit` attributes.

2. Create a `jobs` array and fill it with each `Job`.

3. Sort the `jobs` array based on the end time of the jobs.

4. Define a helper function `findNextJob` that returns the index of the next job that can be taken after the job at index `i`. The next job should have a start time greater than or equal to the end time of the job at index `i`. If there is no such job, return `-1`.

5. Define a memoized helper function `maxProfitHelper` that returns the maximum profit that can be achieved by taking the jobs from index `i` to the end of the array. If `i` is `-1`, return `0`.

* Calculate the index of the next job that can be taken after the job at index `i` using `findNextJob`.

* Calculate the possible maximum profit when including the job at index `i`: this is equal to the profit of job `i` plus the maximum profit that can be achieved by taking the jobs after the job at index `i`.

* Calculate the possible maximum profit when excluding the job at index `i`: this is equal to the maximum profit that can be achieved by taking the jobs from index `i - 1`.

* Memoize the result as the maximum of the maximum profit when including the job and the maximum profit when excluding the job, and return the memoized result.

6. Call the `maxProfitHelper` function with the `jobs` array and `i` as the last index of the `jobs` array. This will return the maximum profit that can be achieved by taking the jobs without overlapping.

## A solution in C++

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

using namespace std;

struct Job {
    int start;
    int end;
    int profit;
};

int findNextJob(vector<Job>& jobs, int i) {
    for (int j = i + 1; j < jobs.size(); j++) {
        if (jobs[j].start >= jobs[i].end) {
            return j;
        }
    }
    return -1;
}

int maxProfitHelper(vector<Job>& jobs, vector<int>& memo, int i) {
    if (i == -1) return 0;
    if (memo[i] != -1) return memo[i];

    int nextJob = findNextJob(jobs, i);
    int inclCurrJob = jobs[i].profit + maxProfitHelper(jobs, memo, nextJob);
    int exclCurrJob = maxProfitHelper(jobs, memo, i - 1);

    memo[i] = max(inclCurrJob, exclCurrJob);
    return memo[i];
}

int maxProfit(vector<int>& startTime, vector<int>& endTime, vector<int>& profit) {
    int n = startTime.size();
    vector<Job> jobs(n);

    for (int i = 0; i < n; i++) {
        jobs[i] = {startTime[i], endTime[i], profit[i]};
    }

    sort(jobs.begin(), jobs.end(), [](const Job& a, const Job& b) {
        return a.end < b.end;
    });

    vector<int> memo(n, -1);
    return maxProfitHelper(jobs, memo, n - 1);
}
```
The algorithm uses dynamic programming with memoization to find the maximum profit:

1. Define a `Job` class or struct with `start`, `end`, and `profit` attributes.

2. Create a `jobs` array and fill it with each `Job`.

3. Sort the `jobs` array based on the end time of the jobs.

4. Define a helper function `findNextJob` that returns the index of the next job that can be taken after the job at index `i`. The next job should have a start time greater than or equal to the end time of the job at index `i`. If there is no such job, return `-1`.

5. Define a memoized helper function `maxProfitHelper` that returns the maximum profit that can be achieved by taking the jobs from index `i` to the end of the array. If `i` is `-1`, return `0`.

* Calculate the index of the next job that can be taken after the job at index `i` using `findNextJob`.

* Calculate the possible maximum profit when including the job at index `i`: this is equal to the profit of job `i` plus the maximum profit that can be achieved by taking the jobs after the job at index `i`.

* Calculate the possible maximum profit when excluding the job at index `i`: this is equal to the maximum profit that can be achieved by taking the jobs from index `i - 1`.

* Memoize the result as the maximum of the maximum profit when including the job and the maximum profit when excluding the job, and return the memoized result.

6. Call the `maxProfitHelper` function with the `jobs` array and `i` as the last index of the `jobs` array. This will return the maximum profit that can be achieved by taking the jobs without overlapping.

## A solution in Python

```python
from functools import lru_cache

class Job:
    def __init__(self, start, end, profit):
        self.start = start
        self.end = end
        self.profit = profit

def find_next_job(jobs, i):
    for j in range(i + 1, len(jobs)):
        if jobs[j].start >= jobs[i].end:
            return j
    return -1

@lru_cache(None)
def max_profit_helper(jobs, i):
    if i == -1:
        return 0

    next_job = find_next_job(jobs, i)
    incl_curr_job = jobs[i].profit + max_profit_helper(jobs, next_job)
    excl_curr_job = max_profit_helper(jobs, i - 1)

    return max(incl_curr_job, excl_curr_job)

def max_profit(startTime, endTime, profit):
    n = len(startTime)
    jobs = [Job(startTime[i], endTime[i], profit[i]) for i in range(n)]

    jobs.sort(key=lambda job: job.end)

    return max_profit_helper(tuple(jobs), n - 1)
```
The algorithm uses dynamic programming with memoization to find the maximum profit:

1. Define a `Job` class or struct with `start`, `end`, and `profit` attributes.

2. Create a `jobs` array and fill it with each `Job`.

3. Sort the `jobs` array based on the end time of the jobs.

4. Define a helper function `findNextJob` that returns the index of the next job that can be taken after the job at index `i`. The next job should have a start time greater than or equal to the end time of the job at index `i`. If there is no such job, return `-1`.

5. Define a memoized helper function `maxProfitHelper` that returns the maximum profit that can be achieved by taking the jobs from index `i` to the end of the array. If `i` is `-1`, return `0`.

* Calculate the index of the next job that can be taken after the job at index `i` using `findNextJob`.

* Calculate the possible maximum profit when including the job at index `i`: this is equal to the profit of job `i` plus the maximum profit that can be achieved by taking the jobs after the job at index `i`.

* Calculate the possible maximum profit when excluding the job at index `i`: this is equal to the maximum profit that can be achieved by taking the jobs from index `i - 1`.

* Memoize the result as the maximum of the maximum profit when including the job and the maximum profit when excluding the job, and return the memoized result.

6. Call the `maxProfitHelper` function with the `jobs` array and `i` as the last index of the `jobs` array. This will return the maximum profit that can be achieved by taking the jobs without overlapping.

## A solution in Javascript

```javascript
class Job {
    constructor(start, end, profit) {
        this.start = start;
        this.end = end;
        this.profit = profit;
    }
}

function findNextJob(jobs, i) {
    for (let j = i + 1; j < jobs.length; j++) {
        if (jobs[j].start >= jobs[i].end) {
            return j;
        }
    }
    return -1;
}

function maxProfitHelper(jobs, memo, i) {
    if (i === -1) return 0;
    if (memo[i] !== -1) return memo[i];

    const nextJob = findNextJob(jobs, i);
    const inclCurrJob = jobs[i].profit + maxProfitHelper(jobs, memo, nextJob);
    const exclCurrJob = maxProfitHelper(jobs, memo, i - 1);

    memo[i] = Math.max(inclCurrJob, exclCurrJob);
    return memo[i];
}

function maxProfit(startTime, endTime, profit) {
    const n = startTime.length;
    const jobs = startTime.map((_, i) => new Job(startTime[i], endTime[i], profit[i]));

    jobs.sort((a, b) => a.end - b.end);

    const memo = Array(n).fill(-1);
    return maxProfitHelper(jobs, memo, n - 1);
}
```
The algorithm uses dynamic programming with memoization to find the maximum profit:

1. Define a `Job` class or struct with `start`, `end`, and `profit` attributes.

2. Create a `jobs` array and fill it with each `Job`.

3. Sort the `jobs` array based on the end time of the jobs.

4. Define a helper function `findNextJob` that returns the index of the next job that can be taken after the job at index `i`. The next job should have a start time greater than or equal to the end time of the job at index `i`. If there is no such job, return `-1`.

5. Define a memoized helper function `maxProfitHelper` that returns the maximum profit that can be achieved by taking the jobs from index `i` to the end of the array. If `i` is `-1`, return `0`.

* Calculate the index of the next job that can be taken after the job at index `i` using `findNextJob`.

* Calculate the possible maximum profit when including the job at index `i`: this is equal to the profit of job `i` plus the maximum profit that can be achieved by taking the jobs after the job at index `i`.

* Calculate the possible maximum profit when excluding the job at index `i`: this is equal to the maximum profit that can be achieved by taking the jobs from index `i - 1`.

* Memoize the result as the maximum of the maximum profit when including the job and the maximum profit when excluding the job, and return the memoized result.

6. Call the `maxProfitHelper` function with the `jobs` array and `i` as the last index of the `jobs` array. This will return the maximum profit that can be achieved by taking the jobs without overlapping.


# Maximum Number of Events That Can Be Attended

- slug: maximum-number-of-events-that-can-be-attended
- difficulty: Medium

You are given an array of `events` where `events[i] = [startDayi, endDayi]`. Every event `i` starts at `startDayi` and ends at `endDayi`.

You can attend an event `i` at any day `d` where `startTimei <= d <= endTimei`. You can only attend one event at any time `d`.

Return _the maximum number of events you can attend_.

**Example 1:**

**Input:** events = \[\[1,2\],\[2,3\],\[3,4\]\]
**Output:** 3
**Explanation:** You can attend all the three events.
One way to attend them all is as shown.
Attend the first event on day 1.
Attend the second event on day 2.
Attend the third event on day 3.

**Example 2:**

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

**Constraints:**

*   `1 <= events.length <= 105`
*   `events[i].length == 2`
*   `1 <= startDayi <= endDayi <= 105`

## A solution in Java

```java
import java.util.*;

public int maxEvents(int[][] events) {
    Arrays.sort(events, (a, b) -> a[0] - b[0]);
    PriorityQueue<Integer> minHeap = new PriorityQueue<>();
    int eventCount = 0, day = 0;

    for (int[] event : events) {
        while (!minHeap.isEmpty() && minHeap.peek() < event[0]) {
            minHeap.poll();
        }
        minHeap.add(event[1]);
        eventCount++;
        day++;
    }

    return eventCount;
}
```
First, we sort the `events` array by its start day in ascending order, using a custom compare function.
Then, we create a min-heap to store the end day of each event.

We initialize `eventCount` and `day` to 0. Then, we iterate through the events.

For each event, we check if the min-heap contains any previously attended events whose end day is less than the start day of the current event. If there are any, we remove them from the min-heap (as they have no impact on the overall count anymore).

After that, we push the end day of the current event into the min-heap and increment both the `eventCount` and `day`.

At the end, we return the `eventCount`, which represents the maximum number of events we could attend.

## A solution in C++

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

using namespace std;

bool compareEvents(const vector<int> &event1, const vector<int> &event2) {
    return event1[0] < event2[0];
}

int maxEvents(vector<vector<int>> &events) {
    sort(events.begin(), events.end(), compareEvents);
    priority_queue<int, vector<int>, greater<int>> minHeap;
    int eventCount = 0, day = 0;

    for (auto &event : events) {
        while (!minHeap.empty() && minHeap.top() < event[0]) {
            minHeap.pop();
        }
        minHeap.push(event[1]);
        eventCount++;
        day++;
    }

    return eventCount;
}
```
First, we sort the `events` array by its start day in ascending order, using a custom compare function.
Then, we create a min-heap to store the end day of each event.

We initialize `eventCount` and `day` to 0. Then, we iterate through the events.

For each event, we check if the min-heap contains any previously attended events whose end day is less than the start day of the current event. If there are any, we remove them from the min-heap (as they have no impact on the overall count anymore).

After that, we push the end day of the current event into the min-heap and increment both the `eventCount` and `day`.

At the end, we return the `eventCount`, which represents the maximum number of events we could attend.

## A solution in Python

```python
import heapq

def maxEvents(events: List[List[int]]) -> int:
    events.sort(key=lambda x: x[0])
    min_heap = []
    event_count, day = 0, 0

    for event in events:
        while min_heap and min_heap[0] < event[0]:
            heapq.heappop(min_heap)
        heapq.heappush(min_heap, event[1])
        event_count += 1
        day += 1

    return event_count
```
First, we sort the `events` array by its start day in ascending order, using a custom compare function.
Then, we create a min-heap to store the end day of each event.

We initialize `eventCount` and `day` to 0. Then, we iterate through the events.

For each event, we check if the min-heap contains any previously attended events whose end day is less than the start day of the current event. If there are any, we remove them from the min-heap (as they have no impact on the overall count anymore).

After that, we push the end day of the current event into the min-heap and increment both the `eventCount` and `day`.

At the end, we return the `eventCount`, which represents the maximum number of events we could attend.

## A solution in Javascript

```javascript
function maxEvents(events) {
    events.sort((a, b) => a[0] - b[0]);
    const minHeap = [];
    let eventCount = 0, day = 0;

    for (let event of events) {
        while (minHeap.length && minHeap[0] < event[0]) {
            minHeap.shift();
        }
        minHeap.push(event[1]);
        minHeap.sort((a, b) => a - b);
        eventCount++;
        day++;
    }

    return eventCount;
}
```
First, we sort the `events` array by its start day in ascending order, using a custom compare function.
Then, we create a min-heap to store the end day of each event.

We initialize `eventCount` and `day` to 0. Then, we iterate through the events.

For each event, we check if the min-heap contains any previously attended events whose end day is less than the start day of the current event. If there are any, we remove them from the min-heap (as they have no impact on the overall count anymore).

After that, we push the end day of the current event into the min-heap and increment both the `eventCount` and `day`.

At the end, we return the `eventCount`, which represents the maximum number of events we could attend.