Facebook Pixel

3115. Maximum Prime Difference

MediumArrayMathNumber Theory
Leetcode Link

Problem Description

You are given an integer array nums.

Your task is to find the maximum distance between the indices of any two prime numbers in the array. The distance is calculated as the difference between their indices.

For example, if you have prime numbers at indices i and j where j > i, the distance would be j - i. You need to find the largest such distance possible.

Note that:

  • The two prime numbers don't have to be different values (they can be the same prime number at different positions)
  • You're looking for the distance between indices, not between the values themselves
  • If there are multiple prime numbers in the array, you want to maximize the distance between any pair of them

The solution approach is straightforward: find the leftmost prime number's index and the rightmost prime number's index in the array, then return their difference. This guarantees the maximum distance since we're spanning from the earliest to the latest occurrence of prime numbers in the array.

Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

To maximize the distance between two prime numbers' indices, we need to think about what creates the largest gap. The distance between any two indices is simply j - i where j > i.

To maximize this difference, we want:

  • i to be as small as possible (leftmost position)
  • j to be as large as possible (rightmost position)

This leads us to a key insight: we don't need to check all pairs of prime numbers. The maximum distance will always be between the first prime number we encounter (smallest index) and the last prime number in the array (largest index).

Why? Because any other pair of primes would have either:

  • A larger starting index (making i bigger, thus reducing j - i)
  • A smaller ending index (making j smaller, thus reducing j - i)
  • Or both

Therefore, our strategy becomes simple:

  1. Find the first prime number while scanning from the left - this gives us the minimum possible i
  2. Find the last prime number while scanning from the right - this gives us the maximum possible j
  3. Return j - i

This greedy approach guarantees we find the maximum distance without needing to compare all possible pairs, making the solution efficient.

Learn more about Math patterns.

Solution Approach

The implementation follows a two-pointer approach to find the maximum distance between prime indices:

Step 1: Helper Function for Prime Checking

First, we define a helper function is_prime(x) to check if a number is prime:

  • If x < 2, return False (0 and 1 are not prime)
  • Check divisibility from 2 to sqrt(x). If x is divisible by any number in this range, it's not prime
  • We only need to check up to sqrt(x) because if x has a divisor greater than sqrt(x), it must also have a corresponding divisor less than sqrt(x)

Step 2: Find the First Prime

We traverse the array from left to right using enumerate(nums):

  • Check each element with is_prime(x)
  • Once we find the first prime, we record its index i
  • This gives us the leftmost prime position

Step 3: Find the Last Prime

After finding the first prime at index i, we search for the last prime:

  • Start from the end of the array at index len(nums) - 1
  • Traverse backwards until index i - 1 (we can stop at i - 1 because we already know there's a prime at index i)
  • Check each element with is_prime(nums[j])
  • The first prime we encounter while going backwards is the rightmost prime

Step 4: Calculate Maximum Distance

Once we find both indices:

  • Return j - i as the maximum distance
  • This works even if i == j (when there's only one prime in the array), giving a distance of 0

The algorithm has a time complexity of O(n * sqrt(m)) where n is the length of the array and m is the maximum value in the array (for prime checking). The space complexity is O(1) as we only use a constant amount of extra space.

Ready to land your dream job?

Unlock your dream job with a 5-minute evaluator for a personalized learning plan!

Start Evaluator

Example Walkthrough

Let's walk through the solution with a concrete example to see how it finds the maximum distance between prime indices.

Example array: nums = [4, 2, 9, 5, 3, 8, 7, 10]

Step 1: Identify which numbers are prime

  • Index 0: 4 → Not prime (divisible by 2)
  • Index 1: 2Prime
  • Index 2: 9 → Not prime (divisible by 3)
  • Index 3: 5Prime
  • Index 4: 3Prime
  • Index 5: 8 → Not prime (divisible by 2)
  • Index 6: 7Prime
  • Index 7: 10 → Not prime (divisible by 2)

Step 2: Find the first (leftmost) prime Starting from index 0 and moving right:

  • Index 0: 4 is not prime, continue
  • Index 1: 2 is prime! Record i = 1

We found our leftmost prime at index 1.

Step 3: Find the last (rightmost) prime Starting from index 7 and moving left:

  • Index 7: 10 is not prime, continue
  • Index 6: 7 is prime! Record j = 6

We found our rightmost prime at index 6.

Step 4: Calculate the maximum distance Maximum distance = j - i = 6 - 1 = 5

Verification: Let's verify this is indeed the maximum by checking all possible prime pairs:

  • Primes at indices: 1, 3, 4, 6
  • Possible distances:
    • (1, 3): distance = 2
    • (1, 4): distance = 3
    • (1, 6): distance = 5 ← Maximum
    • (3, 4): distance = 1
    • (3, 6): distance = 3
    • (4, 6): distance = 2

As expected, the distance between the first prime (index 1) and the last prime (index 6) gives us the maximum distance of 5.

Solution Implementation

1from typing import List
2from math import sqrt
3
4class Solution:
5    def maximumPrimeDifference(self, nums: List[int]) -> int:
6        """
7        Find the maximum difference between indices of two prime numbers in the array.
8        Returns the maximum value of (j - i) where nums[i] and nums[j] are both prime.
9        """
10      
11        def is_prime(n: int) -> bool:
12            """
13            Check if a number is prime.
14          
15            Args:
16                n: Integer to check for primality
17              
18            Returns:
19                True if n is prime, False otherwise
20            """
21            # Numbers less than 2 are not prime
22            if n < 2:
23                return False
24          
25            # Check divisibility from 2 to sqrt(n)
26            # If n is divisible by any number in this range, it's not prime
27            for divisor in range(2, int(sqrt(n)) + 1):
28                if n % divisor == 0:
29                    return False
30          
31            return True
32      
33        # Find the first prime number from the left
34        for left_index, num in enumerate(nums):
35            if is_prime(num):
36                # Once we find the first prime, search for the last prime
37                # Start from the end of the array and move backwards
38                for right_index in range(len(nums) - 1, left_index - 1, -1):
39                    if is_prime(nums[right_index]):
40                        # Return the maximum difference between indices
41                        return right_index - left_index
42      
43        # This line should never be reached if the input guarantees at least one prime
44        return 0
45
1class Solution {
2    /**
3     * Finds the maximum difference between indices of prime numbers in the array.
4     * Returns the difference between the rightmost and leftmost prime number indices.
5     * 
6     * @param nums the input array of integers
7     * @return the maximum difference between prime number indices
8     */
9    public int maximumPrimeDifference(int[] nums) {
10        // Find the leftmost prime number
11        for (int i = 0; ; i++) {
12            if (isPrime(nums[i])) {
13                // Once leftmost prime is found, find the rightmost prime number
14                for (int j = nums.length - 1; ; j--) {
15                    if (isPrime(nums[j])) {
16                        // Return the difference between rightmost and leftmost prime indices
17                        return j - i;
18                    }
19                }
20            }
21        }
22    }
23
24    /**
25     * Checks if a given number is prime.
26     * A prime number is a natural number greater than 1 that has no positive divisors other than 1 and itself.
27     * 
28     * @param x the number to check
29     * @return true if the number is prime, false otherwise
30     */
31    private boolean isPrime(int x) {
32        // Numbers less than 2 are not prime
33        if (x < 2) {
34            return false;
35        }
36      
37        // Check for divisors from 2 up to sqrt(x)
38        // If x has a divisor greater than sqrt(x), it must also have one less than sqrt(x)
39        for (int divisor = 2; divisor * divisor <= x; divisor++) {
40            if (x % divisor == 0) {
41                return false;
42            }
43        }
44      
45        return true;
46    }
47}
48
1class Solution {
2public:
3    /**
4     * Finds the maximum difference between indices of prime numbers in the array
5     * @param nums - input vector of integers
6     * @return maximum difference between the rightmost and leftmost prime indices
7     */
8    int maximumPrimeDifference(vector<int>& nums) {
9        // Find the first prime number from the left
10        for (int i = 0; ; ++i) {
11            if (isPrime(nums[i])) {
12                // Once we find the leftmost prime, search for the rightmost prime
13                for (int j = nums.size() - 1; ; --j) {
14                    if (isPrime(nums[j])) {
15                        // Return the difference between rightmost and leftmost prime indices
16                        return j - i;
17                    }
18                }
19            }
20        }
21    }
22
23    /**
24     * Checks if a given number is prime
25     * @param n - the number to check
26     * @return true if n is prime, false otherwise
27     */
28    bool isPrime(int n) {
29        // Numbers less than 2 are not prime
30        if (n < 2) {
31            return false;
32        }
33      
34        // Check for divisors from 2 to sqrt(n)
35        // Using i <= n/i to avoid overflow and is equivalent to i*i <= n
36        for (int i = 2; i <= n / i; ++i) {
37            if (n % i == 0) {
38                return false;  // Found a divisor, n is not prime
39            }
40        }
41      
42        return true;  // No divisors found, n is prime
43    }
44};
45
1/**
2 * Finds the maximum difference between indices of prime numbers in an array
3 * @param nums - Array of numbers to search for primes
4 * @returns Maximum difference between the rightmost and leftmost prime indices
5 */
6function maximumPrimeDifference(nums: number[]): number {
7    /**
8     * Checks if a number is prime
9     * @param x - Number to check for primality
10     * @returns true if the number is prime, false otherwise
11     */
12    const isPrime = (x: number): boolean => {
13        // Numbers less than 2 are not prime
14        if (x < 2) {
15            return false;
16        }
17      
18        // Check for divisors up to sqrt(x)
19        // Using i <= x / i to avoid potential overflow with i * i <= x
20        for (let i = 2; i <= x / i; i++) {
21            if (x % i === 0) {
22                return false;
23            }
24        }
25      
26        return true;
27    };
28  
29    // Find the leftmost prime number in the array
30    for (let i = 0; i < nums.length; i++) {
31        if (isPrime(nums[i])) {
32            // Once leftmost prime is found, find the rightmost prime
33            for (let j = nums.length - 1; j >= i; j--) {
34                if (isPrime(nums[j])) {
35                    // Return the difference between rightmost and leftmost prime indices
36                    return j - i;
37                }
38            }
39        }
40    }
41  
42    // This return should never be reached if the input contains at least one prime
43    return 0;
44}
45

Time and Space Complexity

Time Complexity: O(n × √M)

The algorithm iterates through the array to find the first prime number, which takes O(n) iterations in the worst case. For each element checked, the is_prime function is called, which has a time complexity of O(√M) where M is the maximum value in the array. This is because is_prime checks divisibility from 2 up to √x.

Once the first prime is found at index i, the algorithm searches backwards from the end of the array to find the last prime. In the worst case, this requires checking O(n) elements again, with each check taking O(√M) time.

Therefore, the overall time complexity is O(n × √M), where n is the length of the array and M is the maximum value in the array.

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space. The is_prime function uses a few variables for iteration and checking, and the main function uses variables i, j, and x for indexing and storing values. No additional data structures that scale with input size are created, resulting in constant space complexity.

Learn more about how to find time and space complexity quickly.

Common Pitfalls

1. Inefficient Prime Checking for Large Numbers

The current implementation checks primality by testing divisibility up to sqrt(n), which can be slow for large numbers. A common mistake is not optimizing the prime checking logic, leading to unnecessary computations.

Issue:

# Current approach checks all numbers from 2 to sqrt(n)
for divisor in range(2, int(sqrt(n)) + 1):
    if n % divisor == 0:
        return False

Solution: Optimize by checking 2 separately, then only odd numbers:

def is_prime(n: int) -> bool:
    if n < 2:
        return False
    if n == 2:
        return True
    if n % 2 == 0:
        return False
  
    # Only check odd divisors from 3 onwards
    for divisor in range(3, int(sqrt(n)) + 1, 2):
        if n % divisor == 0:
            return False
    return True

2. Unnecessary Full Array Traversal

A subtle inefficiency occurs when searching for the last prime. The code correctly stops at left_index - 1, but developers might mistakenly continue searching even after finding both primes.

Issue: Some might write nested loops that don't break properly:

# Inefficient: continues outer loop even after finding the answer
for i, x in enumerate(nums):
    if is_prime(x):
        for j in range(len(nums) - 1, i - 1, -1):
            if is_prime(nums[j]):
                max_dist = j - i  # Doesn't return immediately

Solution: Return immediately once both primes are found (as the current code correctly does).

3. Edge Case: Single Prime Number

While the current solution handles this correctly (returning 0 when i == j), developers might overlook this case and assume there are always at least two distinct prime positions.

Potential mistake:

# Wrong assumption: always different indices
first_prime = -1
last_prime = -1
# ... find primes ...
return last_prime - first_prime  # Could return negative if not handled properly

Solution: The current implementation correctly handles this by searching backwards from the end to left_index - 1, ensuring right_index >= left_index.

4. Integer Overflow in sqrt() Calculation

For very large numbers, int(sqrt(n)) might have precision issues. While rare in typical LeetCode constraints, it's worth considering.

Solution: Use integer-only arithmetic:

def is_prime(n: int) -> bool:
    if n < 2:
        return False
  
    divisor = 2
    while divisor * divisor <= n:
        if n % divisor == 0:
            return False
        divisor += 1 if divisor == 2 else 2
    return True
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

In a binary min heap, the minimum element can be found in:


Recommended Readings

Want a Structured Path to Master System Design Too? Don’t Miss This!

Load More