Problem: Prime Subtraction Operation

You are given a 0-indexed integer array `nums` of length `n`.

You can perform the following operation as many times as you want:

* Pick an index `i` that you haven’t picked before, and pick a prime `p` strictly less than `nums[i]`, then subtract `p` from `nums[i]`.

Return true if you can make `nums` a strictly increasing array using the above
operation and false otherwise.

A strictly increasing array is an array whose each element is strictly greater
than its preceding element.


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 primeSubOperation(self, nums: List[int]) -> bool:
    kMax = 1000
    primes = self._sieveEratosthenes(kMax)

    prevNum = 0
    for num in nums:
      i = bisect.bisect_left(primes, num - prevNum)
      if i > 0:
        num -= primes[i - 1]
      if num <= prevNum:
        return False
      prevNum = num

    return True

  def _sieveEratosthenes(self, n: int) -> List[int]:
    isPrime = [True] * n
    isPrime[0] = False
    isPrime[1] = False
    for i in range(2, int(n**0.5) + 1):
      if isPrime[i]:
        for j in range(i * i, n, i):
          isPrime[j] = False
    return [i for i in range(n) if isPrime[i]]


Java solution:
class Solution {
  public boolean primeSubOperation(int[] nums) {
    final int MAX = 1000;
    final List<Integer> primes = sieveEratosthenes(MAX);

    int prevNum = 0;
    for (int num : nums) {
      // Make nums[i] the smallest as possible and still > nums[i - 1].
      final int i = firstGreaterEqual(primes, num - prevNum);
      if (i > 0)
        num -= primes.get(i - 1);
      if (num <= prevNum)
        return false;
      prevNum = num;
    }

    return true;
  }

  private List<Integer> sieveEratosthenes(int n) {
    List<Integer> primes = new ArrayList<>();
    boolean[] isPrime = new boolean[n];
    Arrays.fill(isPrime, true);
    isPrime[0] = false;
    isPrime[1] = false;
    for (int i = 2; i * i < n; ++i)
      if (isPrime[i])
        for (int j = i * i; j < n; j += i)
          isPrime[j] = false;
    for (int i = 2; i < n; ++i)
      if (isPrime[i])
        primes.add(i);
    return primes;
  }

  private int firstGreaterEqual(List<Integer> A, int target) {
    final int i = Collections.binarySearch(A, target);
    return i < 0 ? -i - 1 : i;
  }
}


C++ solution:
class Solution {
 public:
  bool primeSubOperation(vector<int>& nums) {
    constexpr int kMax = 1000;
    const vector<int> primes = sieveEratosthenes(kMax);

    int prevNum = 0;
    for (int num : nums) {
      // Make nums[i] the smallest as possible and still > nums[i - 1].
      const auto it = ranges::lower_bound(primes, num - prevNum);
      if (it != primes.begin())
        num -= *prev(it);
      if (num <= prevNum)
        return false;
      prevNum = num;
    }

    return true;
  }

  vector<int> sieveEratosthenes(int n) {
    vector<int> primes;
    vector<bool> isPrime(n, true);
    isPrime[0] = false;
    isPrime[1] = false;
    for (int i = 2; i * i < n; ++i)
      if (isPrime[i])
        for (int j = i * i; j < n; j += i)
          isPrime[j] = false;
    for (int i = 2; i < n; ++i)
      if (isPrime[i])
        primes.push_back(i);
    return primes;
  }
};