Skip to content

3629. Minimum Jumps to Reach End via Prime Teleportation

Description

You are given an integer array nums of length n.

You start at index 0, and your goal is to reach index n - 1.

From any index i, you may perform one of the following operations:

  • Adjacent Step: Jump to index i + 1 or i - 1, if the index is within bounds.
  • Prime Teleportation: If nums[i] is a p, you may instantly jump to any index j != i such that nums[j] % p == 0.

Return the minimum number of jumps required to reach index n - 1.

 

Example 1:

Input: nums = [1,2,4,6]

Output: 2

Explanation:

One optimal sequence of jumps is:

  • Start at index i = 0. Take an adjacent step to index 1.
  • At index i = 1, nums[1] = 2 is a prime number. Therefore, we teleport to index i = 3 as nums[3] = 6 is divisible by 2.

Thus, the answer is 2.

Example 2:

Input: nums = [2,3,4,7,9]

Output: 2

Explanation:

One optimal sequence of jumps is:

  • Start at index i = 0. Take an adjacent step to index i = 1.
  • At index i = 1, nums[1] = 3 is a prime number. Therefore, we teleport to index i = 4 since nums[4] = 9 is divisible by 3.

Thus, the answer is 2.

Example 3:

Input: nums = [4,6,5,8]

Output: 3

Explanation:

  • Since no teleportation is possible, we move through 0 → 1 → 2 → 3. Thus, the answer is 3.

 

Constraints:

  • 1 <= n == nums.length <= 105
  • 1 <= nums[i] <= 106

 

Solutions

Solution: Sieve of Eratosthenes + Breadth-First Search

  • Time complexity: O(mloglogm+nlogm)
    • m = Max(nums)
  • Space complexity: O(m+nlogm)

 

JavaScript

js
/**
 * @param {number[]} nums
 * @return {number}
 */
const minJumps = function (nums) {
  const n = nums.length;
  const maxNum = Math.max(...nums);
  const sieve = Array.from({ length: maxNum + 1 }, (_, index) => index);
  const visited = Array.from({ length: n }, () => false);
  const primeSet = new Set();
  const primeMap = new Map();
  let queue = [0];
  let result = 0;

  const isPrime = x => x > 1 && sieve[x] === x;

  for (let a = 2; a ** 2 <= maxNum; a++) {
    if (sieve[a] !== a) continue;

    for (let b = a * a; b <= maxNum; b += a) {
      if (sieve[b] === b) {
        sieve[b] = a;
      }
    }
  }

  for (const num of nums) {
    if (isPrime(num)) {
      primeSet.add(num);
    }
  }

  for (let index = 0; index < n; index++) {
    let current = nums[index];

    while (current > 1) {
      const prime = sieve[current];

      if (primeSet.has(prime)) {
        if (!primeMap.has(prime)) {
          primeMap.set(prime, []);
        }

        primeMap.get(prime).push(index);
      }

      while (current % prime === 0) {
        current /= prime;
      }
    }
  }

  while (queue.length) {
    const nextQueue = [];

    for (const index of queue) {
      if (index === n - 1) return result;

      const num = nums[index];
      const prev = index - 1;
      const next = index + 1;

      if (prev >= 0 && !visited[prev]) {
        visited[prev] = true;
        nextQueue.push(prev);
      }

      if (next < n && !visited[next]) {
        visited[next] = true;
        nextQueue.push(next);
      }

      if (!isPrime(num)) continue;

      for (const pos of primeMap.get(num)) {
        if (pos === index || visited[pos]) continue;

        visited[pos] = true;
        nextQueue.push(pos);
      }

      primeMap.set(num, []);
    }

    queue = nextQueue;
    result += 1;
  }

  return -1;
};

Released under the MIT license