Skip to content

2601. Prime Subtraction Operation 👍

  • Time: $O(n\log(\log n))$
  • Space: $O(n)$
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
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;
  }
};
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
class Solution {
  public boolean primeSubOperation(int[] nums) {
    final int kMax = 1000;
    final List<Integer> primes = sieveEratosthenes(kMax);

    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;
  }
}
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution:
  def primeSubOperation(self, nums: List[int]) -> bool:
    kMax = 1000
    primes = self._sieveEratosthenes(kMax)

    prevNum = 0
    for num in nums:
      # Make nums[i] the smallest as possible and still > nums[i - 1].
      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]]