Facebook Pixel

3618. Split Array by Prime Indices

MediumArrayMathNumber Theory
Leetcode Link

Problem Description

You are given an integer array nums.

Your task is to split the array into two separate arrays A and B based on the following rule:

  • Elements at prime indices in nums go into array A
  • All other elements go into array B

A prime index is an index position that is a prime number. For example:

  • Index 2 is prime (goes to A)
  • Index 3 is prime (goes to A)
  • Index 0 is not prime (goes to B)
  • Index 1 is not prime (goes to B)
  • Index 4 is not prime (goes to B)
  • Index 5 is prime (goes to A)

After splitting the elements into the two arrays, calculate the sum of each array and return the absolute difference between these sums: |sum(A) - sum(B)|.

If either array ends up empty, its sum is considered to be 0.

Example walkthrough: If nums = [10, 20, 30, 40, 50, 60]:

  • Prime indices: 2, 3, 5
  • Array A gets elements at indices 2, 3, 5: [30, 40, 60] with sum = 130
  • Array B gets elements at indices 0, 1, 4: [10, 20, 50] with sum = 80
  • Result: |130 - 80| = 50
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is recognizing that we don't actually need to create two separate arrays. Instead, we can think about the problem as calculating a running difference.

When we split elements into two groups and want to find |sum(A) - sum(B)|, we can reframe this mathematically. Each element either contributes positively to one sum or to the other. If an element goes to array A, it increases the difference by that amount. If it goes to array B, it decreases the difference by that amount.

So we can iterate through the array once and for each element:

  • If its index is prime → add it to our running total (as if adding to sum(A))
  • If its index is not prime → subtract it from our running total (as if adding to sum(B))

This gives us sum(A) - sum(B) directly. Taking the absolute value gives us our answer.

The elegance of this approach is that sum(x if primes[i] else -x for i, x in enumerate(nums)) computes exactly sum(A) - sum(B) in a single pass. Each element at a prime index contributes positively, while each element at a non-prime index contributes negatively.

For determining which indices are prime, since we're dealing with array indices that could go up to 10^5, we can efficiently precompute all primes up to this range using the Sieve of Eratosthenes algorithm. This is much faster than checking each index individually for primality, especially when dealing with multiple test cases.

Learn more about Math patterns.

Solution Approach

The solution uses the Sieve of Eratosthenes algorithm for preprocessing prime numbers, combined with a clever simulation technique to calculate the result.

Step 1: Precompute Prime Numbers

We first create a boolean array primes of size 10^5 + 10 to mark which numbers are prime:

  • Initialize all values to True
  • Mark primes[0] = False and primes[1] = False (0 and 1 are not prime)
  • For each number i from 2 to m:
    • If i is still marked as prime, mark all its multiples as non-prime
    • This is done by iterating through j = i+i, i+2i, i+3i, ... and setting primes[j] = False

This preprocessing runs once and gives us O(1) lookup for checking if any index is prime.

Step 2: Calculate the Sum Difference

Instead of creating two separate arrays, we use a mathematical trick:

  • Iterate through nums with enumerate() to get both index i and value x
  • For each element:
    • If primes[i] is True → add x to the sum (element goes to array A)
    • If primes[i] is False → subtract x from the sum (element goes to array B)

This is elegantly expressed as: sum(x if primes[i] else -x for i, x in enumerate(nums))

This single expression computes sum(A) - sum(B) directly because:

  • Elements at prime indices contribute positively (+x)
  • Elements at non-prime indices contribute negatively (-x)

Step 3: Return Absolute Value

Since we need |sum(A) - sum(B)|, we wrap the entire calculation in abs().

The time complexity is O(n) for processing the array, with O(m log log m) preprocessing for the sieve. The space complexity is O(m) for storing the prime number lookup table.

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 a small example with nums = [5, 8, 2, 7, 3].

Step 1: Identify Prime Indices Using our precomputed sieve, we check each index:

  • Index 0: Not prime (0 is never prime)
  • Index 1: Not prime (1 is never prime)
  • Index 2: Prime ✓
  • Index 3: Prime ✓
  • Index 4: Not prime (4 = 2×2)

Step 2: Apply the Mathematical Trick Instead of creating two arrays, we calculate the running difference:

  • Index 0 (value=5): Not prime → contribute -5 to sum
  • Index 1 (value=8): Not prime → contribute -8 to sum
  • Index 2 (value=2): Prime → contribute +2 to sum
  • Index 3 (value=7): Prime → contribute +7 to sum
  • Index 4 (value=3): Not prime → contribute -3 to sum

Running calculation: -5 + (-8) + 2 + 7 + (-3) = -7

Step 3: Take Absolute Value Result = |-7| = 7

Verification with Traditional Approach:

  • Array A (prime indices 2, 3): [2, 7] → sum = 9
  • Array B (non-prime indices 0, 1, 4): [5, 8, 3] → sum = 16
  • Difference: |9 - 16| = 7

This demonstrates how the single-pass calculation sum(x if primes[i] else -x for i, x in enumerate(nums)) directly computes the difference without actually creating the two arrays.

Solution Implementation

1from typing import List
2
3# Sieve of Eratosthenes to precompute prime numbers up to 10^5 + 10
4MAX_SIZE = 10**5 + 10
5is_prime = [True] * MAX_SIZE
6is_prime[0] = is_prime[1] = False  # 0 and 1 are not prime
7
8# Mark all multiples of prime numbers as not prime
9for i in range(2, MAX_SIZE):
10    if is_prime[i]:
11        # Mark all multiples of i as not prime
12        for j in range(i * 2, MAX_SIZE, i):
13            is_prime[j] = False
14
15
16class Solution:
17    def splitArray(self, nums: List[int]) -> int:
18        """
19        Calculate the absolute difference between sum of elements at prime indices
20        and sum of elements at non-prime indices.
21      
22        Args:
23            nums: List of integers
24          
25        Returns:
26            The absolute value of the difference between the two sums
27        """
28        # Sum elements at prime indices (positive) and non-prime indices (negative)
29        # Then take absolute value of the total
30        total_sum = sum(
31            nums[i] if is_prime[i] else -nums[i] 
32            for i in range(len(nums))
33        )
34        return abs(total_sum)
35
1class Solution {
2    // Maximum limit for prime number generation
3    private static final int MAX_LIMIT = 100010;
4  
5    // Boolean array to mark prime numbers (true = prime, false = not prime)
6    private static boolean[] isPrime = new boolean[MAX_LIMIT];
7
8    // Static initialization block to generate all prime numbers up to MAX_LIMIT
9    // using the Sieve of Eratosthenes algorithm
10    static {
11        // Initially mark all numbers as prime
12        for (int i = 0; i < MAX_LIMIT; i++) {
13            isPrime[i] = true;
14        }
15      
16        // 0 and 1 are not prime numbers
17        isPrime[0] = false;
18        isPrime[1] = false;
19
20        // Sieve of Eratosthenes algorithm
21        for (int i = 2; i < MAX_LIMIT; i++) {
22            if (isPrime[i]) {
23                // Mark all multiples of i as non-prime
24                for (int multiple = i + i; multiple < MAX_LIMIT; multiple += i) {
25                    isPrime[multiple] = false;
26                }
27            }
28        }
29    }
30
31    /**
32     * Splits the array based on prime indices.
33     * Adds values at prime indices and subtracts values at non-prime indices,
34     * then returns the absolute value of the sum.
35     * 
36     * @param nums the input array to process
37     * @return the absolute value of the weighted sum
38     */
39    public long splitArray(int[] nums) {
40        long weightedSum = 0;
41      
42        // Iterate through the array
43        for (int index = 0; index < nums.length; index++) {
44            // Add value if index is prime, subtract if not
45            if (isPrime[index]) {
46                weightedSum += nums[index];
47            } else {
48                weightedSum -= nums[index];
49            }
50        }
51      
52        // Return the absolute value of the weighted sum
53        return Math.abs(weightedSum);
54    }
55}
56
1// Constants
2const int MAX_SIZE = 1e5 + 10;
3
4// Global array to store prime number flags
5bool isPrime[MAX_SIZE];
6
7// Initialize prime number sieve using Sieve of Eratosthenes
8// This lambda function executes immediately to initialize the prime array
9auto initialize = [] {
10    // Initially mark all numbers as prime
11    memset(isPrime, true, sizeof(isPrime));
12  
13    // 0 and 1 are not prime numbers
14    isPrime[0] = isPrime[1] = false;
15  
16    // Sieve of Eratosthenes algorithm
17    for (int i = 2; i < MAX_SIZE; ++i) {
18        if (isPrime[i]) {
19            // Mark all multiples of i as non-prime
20            for (int j = i + i; j < MAX_SIZE; j += i) {
21                isPrime[j] = false;
22            }
23        }
24    }
25    return 0;
26}();
27
28class Solution {
29public:
30    /**
31     * Splits array based on prime indices and calculates the absolute difference
32     * 
33     * The algorithm adds values at prime indices and subtracts values at non-prime indices,
34     * then returns the absolute value of the result.
35     * 
36     * @param nums Input vector of integers
37     * @return Absolute value of the sum after applying prime index rules
38     */
39    long long splitArray(vector<int>& nums) {
40        long long result = 0;
41      
42        // Iterate through each element in the array
43        for (int i = 0; i < nums.size(); ++i) {
44            // Add value if index is prime, subtract if index is not prime
45            result += isPrime[i] ? nums[i] : -nums[i];
46        }
47      
48        // Return the absolute value of the calculated sum
49        return abs(result);
50    }
51};
52
1// Maximum value for prime sieve
2const MAX_VALUE = 100000 + 10;
3
4// Boolean array to mark prime numbers (true = prime, false = not prime)
5const isPrime: boolean[] = Array(MAX_VALUE).fill(true);
6
7// Initialize the prime sieve using Sieve of Eratosthenes algorithm
8const initializePrimeSieve = (() => {
9    // 0 and 1 are not prime numbers
10    isPrime[0] = isPrime[1] = false;
11
12    // Sieve of Eratosthenes: mark all multiples of prime numbers as non-prime
13    for (let i = 2; i < MAX_VALUE; i++) {
14        if (isPrime[i]) {
15            // Mark all multiples of i as non-prime
16            for (let j = i + i; j < MAX_VALUE; j += i) {
17                isPrime[j] = false;
18            }
19        }
20    }
21})();
22
23/**
24 * Splits an array by assigning positive or negative signs based on prime indices
25 * @param nums - The input array of numbers
26 * @returns The absolute value of the sum after applying signs based on prime indices
27 */
28function splitArray(nums: number[]): number {
29    let sum = 0;
30  
31    // Add positive value if index is prime, negative value if index is not prime
32    for (let i = 0; i < nums.length; i++) {
33        sum += isPrime[i] ? nums[i] : -nums[i];
34    }
35  
36    // Return the absolute value of the final sum
37    return Math.abs(sum);
38}
39

Time and Space Complexity

The code consists of two parts: preprocessing to generate prime numbers using the Sieve of Eratosthenes, and the main solution.

Preprocessing (Sieve of Eratosthenes):

  • Time Complexity: O(m log log m) where m = 10^5 + 10
  • Space Complexity: O(m) for the primes boolean array

Main Solution (splitArray method):

  • Time Complexity: O(n) where n is the length of the input array nums. The solution iterates through the array once, performing constant-time operations (checking prime status and arithmetic operations) for each element.
  • Space Complexity: O(1) excluding the preprocessed primes array. The generator expression computes the sum on-the-fly without creating additional data structures proportional to the input size.

Following the reference answer's convention of ignoring preprocessing time and space:

  • Time Complexity: O(n) where n is the length of the array nums
  • Space Complexity: O(1)

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

Common Pitfalls

1. Index Out of Bounds for Prime Check

The most critical pitfall is assuming the input array size won't exceed the precomputed prime table size. If len(nums) exceeds MAX_SIZE, the code will crash with an IndexError when checking is_prime[i].

Example scenario: If nums has 100,011 elements, accessing is_prime[100010] will fail since our table only goes up to 100,010.

Solution:

class Solution:
    def splitArray(self, nums: List[int]) -> int:
        # Dynamically check if we need to extend the prime table
        max_index = len(nums) - 1
        if max_index >= len(is_prime):
            # Either extend the sieve or handle inline
            return self._handle_large_input(nums)
      
        total_sum = sum(
            nums[i] if is_prime[i] else -nums[i] 
            for i in range(len(nums))
        )
        return abs(total_sum)

2. Global State Mutation Risk

Using a global is_prime array outside the class can lead to issues in concurrent environments or when the array needs to be modified. If another part of the code accidentally modifies is_prime, all subsequent calls will produce incorrect results.

Solution: Encapsulate the prime computation within the class or use a class variable:

class Solution:
    def __init__(self):
        self.is_prime = self._compute_primes(10**5 + 10)
  
    def _compute_primes(self, limit):
        primes = [True] * limit
        primes[0] = primes[1] = False
        for i in range(2, int(limit**0.5) + 1):
            if primes[i]:
                for j in range(i*i, limit, i):
                    primes[j] = False
        return primes

3. Integer Overflow in Large Sums

While Python handles arbitrary precision integers automatically, in other languages or constrained environments, the sum calculation might overflow for very large arrays with large values.

Solution: Consider using modular arithmetic if required by the problem constraints, or explicitly handle large number scenarios:

def splitArray(self, nums: List[int]) -> int:
    sum_a = sum_b = 0
    for i, val in enumerate(nums):
        if is_prime[i]:
            sum_a += val
        else:
            sum_b += val
    # Check for potential overflow scenarios if needed
    return abs(sum_a - sum_b)

4. Inefficient Sieve Implementation

The current sieve marks all multiples starting from i * 2. This is less efficient than starting from i * i since all smaller multiples would have already been marked by smaller primes.

Solution: Optimize the sieve:

for i in range(2, int(MAX_SIZE**0.5) + 1):
    if is_prime[i]:
        # Start from i*i instead of i*2
        for j in range(i * i, MAX_SIZE, i):
            is_prime[j] = False
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

What's the relationship between a tree and a graph?


Recommended Readings

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

Load More