Problem: Jump Game V

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.


Python solution:
import math
import itertools
import bisect
import collections
import string
import heapq
import functools
import sortedcontainers
from typing import List, Dict, Tuple, Iterator

class Solution:
  def maxJumps(self, arr: List[int], d: int) -> int:
    n = len(arr)
    dp = [1] * n
    stack = []

    for i in range(n + 1):
      while stack and (i == n or arr[stack[-1]] < arr[i]):
        indices = [stack.pop()]
        while stack and arr[stack[-1]] == arr[indices[0]]:
          indices.append(stack.pop())
        for j in indices:
          if i < n and i - j <= d:
            dp[i] = max(dp[i], dp[j] + 1)
          if stack and j - stack[-1] <= d:
            dp[stack[-1]] = max(dp[stack[-1]], dp[j] + 1)
      stack.append(i)

    return max(dp)


Java solution:
class Solution {
  public int maxJumps(int[] arr, int d) {
    final int n = arr.length;
    // dp[i] := the maximum jumps starting from arr[i]
    int[] dp = new int[n];
    // a dcreasing stack that stores indices
    Deque<Integer> stack = new ArrayDeque<>();

    for (int i = 0; i <= n; ++i) {
      while (!stack.isEmpty() && (i == n || arr[stack.peek()] < arr[i])) {
        List<Integer> indices = new ArrayList<>(List.of(stack.pop()));
        while (!stack.isEmpty() && arr[stack.peek()] == arr[indices.get(0)])
          indices.add(stack.pop());
        for (final int j : indices) {
          if (i < n && i - j <= d)
            // Can jump from i to j.
            dp[i] = Math.max(dp[i], dp[j] + 1);
          if (!stack.isEmpty() && j - stack.peek() <= d)
            // Can jump from stack.peek() to j
            dp[stack.peek()] = Math.max(dp[stack.peek()], dp[j] + 1);
        }
      }
      stack.push(i);
    }

    return Arrays.stream(dp).max().getAsInt() + 1;
  }
}


C++ solution:
class Solution {
 public:
  int maxJumps(vector<int>& arr, int d) {
    const int n = arr.size();
    // dp[i] := the maximum jumps starting from arr[i]
    vector<int> dp(n, 1);
    // a dcreasing stack that stores indices
    stack<int> stack;

    for (int i = 0; i <= n; ++i) {
      while (!stack.empty() && (i == n || arr[stack.top()] < arr[i])) {
        vector<int> indices{stack.top()};
        stack.pop();
        while (!stack.empty() && arr[stack.top()] == arr[indices[0]])
          indices.push_back(stack.top()), stack.pop();
        for (const int j : indices) {
          if (i < n && i - j <= d)
            // Can jump from i to j.
            dp[i] = max(dp[i], dp[j] + 1);
          if (!stack.empty() && j - stack.top() <= d)
            // Can jump from stack[-1] to j.
            dp[stack.top()] = max(dp[stack.top()], dp[j] + 1);
        }
      }
      stack.push(i);
    }

    return ranges::max(dp);
  }
};