2761. Prime Pairs With Target Sum
Problem Description
Given an integer n
, you need to find all pairs of prime numbers (x, y)
that satisfy the following conditions:
- Both
x
andy
must be prime numbers x + y
must equaln
1 <= x <= y <= n
Return a 2D list containing all valid prime number pairs [x, y]
. The list should be sorted in increasing order of x
. If no valid prime pairs exist, return an empty array.
A prime number is defined as a natural number greater than 1 that has exactly two factors: 1 and itself.
For example, if n = 12
, the valid prime pairs would be [[5, 7]]
because:
- 5 and 7 are both prime numbers
- 5 + 7 = 12
- 5 <= 7
The solution uses the Sieve of Eratosthenes algorithm to efficiently find all prime numbers up to n
. It creates a boolean array primes
where primes[i]
indicates whether i
is prime. Then it iterates through all possible values of x
from 2 to n//2
, calculates y = n - x
, and checks if both x
and y
are prime. If they are, the pair [x, y]
is added to the result.
The reason for only checking x
up to n//2
is to ensure x <= y
. Since x + y = n
, when x > n//2
, we would have y < x
, which violates the constraint x <= y
.
Intuition
The key insight is that we need to find two prime numbers that sum to n
. Since we're looking for pairs (x, y)
where x + y = n
, once we choose a value for x
, the value of y
is automatically determined as y = n - x
.
This transforms our problem from finding pairs to simply iterating through possible values of x
and checking if both x
and its complement n - x
are prime.
To avoid duplicate pairs and ensure x <= y
, we only need to check values of x
up to n/2
. Why? Because if x > n/2
, then y = n - x < n/2
, which means y < x
. This would give us the same pair but in reverse order, which we want to avoid.
The most time-consuming part would be checking if numbers are prime. If we checked primality for each number individually using trial division, it would be inefficient. Instead, we can pre-compute all prime numbers up to n
using the Sieve of Eratosthenes algorithm. This gives us O(1)
lookup time to check if any number is prime.
The Sieve works by initially assuming all numbers are prime, then systematically marking multiples of each prime as composite. After this preprocessing, we have a boolean array where we can instantly check if any number up to n
is prime.
With this setup, the solution becomes straightforward:
- Pre-compute all primes up to
n
- For each potential
x
from 2 ton/2
, check if bothx
andn - x
are prime - If both are prime, add the pair
[x, n - x]
to our answer
Learn more about Math patterns.
Solution Approach
The solution consists of two main phases: preprocessing prime numbers and finding valid pairs.
Phase 1: Prime Number Preprocessing using Sieve of Eratosthenes
We create a boolean array primes
of size n
where primes[i]
indicates whether i
is prime. Initially, we assume all numbers are prime by setting all values to True
.
primes = [True] * n
Then we implement the Sieve of Eratosthenes:
- Start iterating from
i = 2
(the smallest prime) - If
primes[i]
isTrue
, theni
is prime - Mark all multiples of
i
(starting from2i
, then3i
,4i
, etc.) asFalse
since they're composite - Continue this process for all numbers up to
n
for i in range(2, n):
if primes[i]:
for j in range(i + i, n, i):
primes[j] = False
The inner loop range(i + i, n, i)
generates multiples of i
starting from 2i
up to n-1
with step size i
.
Phase 2: Finding Prime Pairs
After preprocessing, we enumerate all possible values of x
:
- We iterate
x
from 2 ton // 2 + 1
(inclusive ofn // 2
) - For each
x
, we calculatey = n - x
- Check if both
x
andy
are prime using our preprocessed array - If both are prime, add the pair
[x, y]
to our answer
ans = []
for x in range(2, n // 2 + 1):
y = n - x
if primes[x] and primes[y]:
ans.append([x, y])
The range (2, n // 2 + 1)
ensures:
- We start from 2 (the smallest prime)
- We stop at
n // 2
to maintainx <= y
- The pairs are automatically sorted by
x
since we iterate in increasing order
Time Complexity: O(n log log n)
for the Sieve of Eratosthenes + O(n)
for finding pairs = O(n log log n)
Space Complexity: O(n)
for the primes
array
Ready to land your dream job?
Unlock your dream job with a 5-minute evaluator for a personalized learning plan!
Start EvaluatorExample Walkthrough
Let's walk through the solution with n = 12
.
Step 1: Create Prime Sieve
First, we create a boolean array primes
of size 12 and initialize all values to True
:
Index: 0 1 2 3 4 5 6 7 8 9 10 11 Value: T T T T T T T T T T T T
Step 2: Apply Sieve of Eratosthenes
Starting with i = 2
(prime):
- Mark multiples of 2: positions 4, 6, 8, 10 become
False
With i = 3
(prime):
- Mark multiples of 3: positions 6, 9 become
False
(6 already marked)
With i = 4
: Already marked as False
, skip
With i = 5
(prime):
- Mark multiples of 5: position 10 already
False
With i = 6
: Already marked as False
, skip
With i = 7
(prime):
- No multiples within range to mark
Continue until i = 11
...
Final primes
array:
Index: 0 1 2 3 4 5 6 7 8 9 10 11 Value: F F T T F T F T F F F T
Primes are: 2, 3, 5, 7, 11
Step 3: Find Prime Pairs
Iterate x
from 2 to n // 2 = 6
:
-
x = 2
:y = 12 - 2 = 10
- Is 2 prime? Yes (
primes[2] = True
) - Is 10 prime? No (
primes[10] = False
) - Don't add this pair
- Is 2 prime? Yes (
-
x = 3
:y = 12 - 3 = 9
- Is 3 prime? Yes (
primes[3] = True
) - Is 9 prime? No (
primes[9] = False
) - Don't add this pair
- Is 3 prime? Yes (
-
x = 4
:y = 12 - 4 = 8
- Is 4 prime? No (
primes[4] = False
) - Skip
- Is 4 prime? No (
-
x = 5
:y = 12 - 5 = 7
- Is 5 prime? Yes (
primes[5] = True
) - Is 7 prime? Yes (
primes[7] = True
) - Add pair
[5, 7]
to result
- Is 5 prime? Yes (
-
x = 6
:y = 12 - 6 = 6
- Is 6 prime? No (
primes[6] = False
) - Skip
- Is 6 prime? No (
Result: [[5, 7]]
The algorithm correctly identifies that only the prime pair (5, 7) sums to 12.
Solution Implementation
1from typing import List
2
3class Solution:
4 def findPrimePairs(self, n: int) -> List[List[int]]:
5 """
6 Find all pairs of prime numbers [x, y] where x + y = n and x <= y.
7
8 Args:
9 n: Target sum for the prime pairs
10
11 Returns:
12 List of prime pairs [x, y] sorted by x in ascending order
13 """
14 # Initialize a boolean array to track prime numbers using Sieve of Eratosthenes
15 # Index represents the number, value represents whether it's prime
16 is_prime = [True] * n
17
18 # 0 and 1 are not prime numbers
19 if n > 0:
20 is_prime[0] = False
21 if n > 1:
22 is_prime[1] = False
23
24 # Sieve of Eratosthenes algorithm to find all primes less than n
25 for i in range(2, n):
26 if is_prime[i]:
27 # Mark all multiples of i as non-prime
28 for j in range(i * 2, n, i):
29 is_prime[j] = False
30
31 # Find all valid prime pairs
32 result = []
33
34 # Only need to check x from 2 to n//2 since we want x <= y
35 # If x > n//2, then y = n - x < n//2 < x, violating x <= y
36 for x in range(2, n // 2 + 1):
37 y = n - x
38
39 # Check if both x and y are prime numbers
40 if is_prime[x] and is_prime[y]:
41 result.append([x, y])
42
43 return result
44
1class Solution {
2 /**
3 * Finds all pairs of prime numbers (x, y) where x + y = n and x <= y.
4 *
5 * @param n The target sum for prime pairs
6 * @return List of prime pairs [x, y] where x + y = n
7 */
8 public List<List<Integer>> findPrimePairs(int n) {
9 // Generate all prime numbers up to n using Sieve of Eratosthenes
10 boolean[] isPrime = new boolean[n];
11 Arrays.fill(isPrime, true);
12
13 // Sieve of Eratosthenes algorithm
14 // Mark all non-prime numbers as false
15 for (int i = 2; i < n; i++) {
16 if (isPrime[i]) {
17 // Mark all multiples of i as non-prime
18 for (int multiple = i + i; multiple < n; multiple += i) {
19 isPrime[multiple] = false;
20 }
21 }
22 }
23
24 // Find all valid prime pairs
25 List<List<Integer>> result = new ArrayList<>();
26
27 // Iterate through first half of possible values (x <= n/2)
28 // This ensures x <= y since y = n - x
29 for (int x = 2; x <= n / 2; x++) {
30 int y = n - x;
31
32 // Check if both x and y are prime numbers
33 if (isPrime[x] && isPrime[y]) {
34 result.add(List.of(x, y));
35 }
36 }
37
38 return result;
39 }
40}
41
1class Solution {
2public:
3 vector<vector<int>> findPrimePairs(int n) {
4 // Create a boolean array to track prime numbers using Sieve of Eratosthenes
5 // Initially assume all numbers are prime (true)
6 bool isPrime[n];
7 memset(isPrime, true, sizeof(isPrime));
8
9 // Sieve of Eratosthenes algorithm to find all primes less than n
10 // Start from 2 (smallest prime number)
11 for (int i = 2; i < n; ++i) {
12 if (isPrime[i]) {
13 // Mark all multiples of i as non-prime
14 // Start from i*2 and increment by i each time
15 for (int j = i * 2; j < n; j += i) {
16 isPrime[j] = false;
17 }
18 }
19 }
20
21 // Store all valid prime pairs
22 vector<vector<int>> result;
23
24 // Find all prime pairs (x, y) where x + y = n
25 // Only check x up to n/2 to avoid duplicate pairs
26 for (int x = 2; x <= n / 2; ++x) {
27 int y = n - x; // Calculate corresponding y value
28
29 // Check if both x and y are prime numbers
30 if (isPrime[x] && isPrime[y]) {
31 result.push_back({x, y});
32 }
33 }
34
35 return result;
36 }
37};
38
1/**
2 * Finds all pairs of prime numbers that sum up to n
3 * @param n - The target sum for prime pairs
4 * @returns Array of prime pairs [x, y] where x + y = n and x <= y
5 */
6function findPrimePairs(n: number): number[][] {
7 // Initialize boolean array to track prime numbers using Sieve of Eratosthenes
8 // Index represents the number, value represents if it's prime
9 const isPrime: boolean[] = new Array(n).fill(true);
10
11 // Mark 0 and 1 as non-prime (implicitly handled since we start from 2)
12 // Apply Sieve of Eratosthenes algorithm
13 for (let i = 2; i < n; i++) {
14 if (isPrime[i]) {
15 // Mark all multiples of i as non-prime
16 for (let j = i * 2; j < n; j += i) {
17 isPrime[j] = false;
18 }
19 }
20 }
21
22 // Store the result pairs
23 const result: number[][] = [];
24
25 // Find all prime pairs (x, y) where x + y = n
26 // Only check up to n/2 to avoid duplicate pairs
27 for (let x = 2; x <= Math.floor(n / 2); x++) {
28 const y: number = n - x;
29
30 // Check if both x and y are prime numbers
31 if (isPrime[x] && isPrime[y]) {
32 result.push([x, y]);
33 }
34 }
35
36 return result;
37}
38
Time and Space Complexity
Time Complexity: O(n log log n)
The time complexity is dominated by the Sieve of Eratosthenes algorithm used to find all prime numbers up to n
.
- The outer loop runs from
2
ton
, iteratingO(n)
times. - For each prime number
i
, the inner loop marks its multiples as non-prime, runningn/i
times. - The total number of operations is approximately
n/2 + n/3 + n/5 + n/7 + ... = n × (1/2 + 1/3 + 1/5 + 1/7 + ...)
for all primes up ton
. - The sum of reciprocals of primes up to
n
isO(log log n)
, making the sieve portionO(n log log n)
. - The second loop to find prime pairs runs
O(n/2)
times withO(1)
operations per iteration, contributingO(n)
time. - Overall time complexity:
O(n log log n) + O(n) = O(n log log n)
.
Space Complexity: O(n)
- The
primes
boolean array storesn
elements, requiringO(n)
space. - The
ans
list stores the prime pairs, which in the worst case could beO(n)
pairs (though typically much fewer). - Additional variables use constant space
O(1)
. - Overall space complexity:
O(n)
.
Learn more about how to find time and space complexity quickly.
Common Pitfalls
1. Index Out of Bounds Error
One of the most common mistakes is not handling edge cases properly when initializing the is_prime
array, especially for small values of n
.
Problematic Code:
is_prime = [True] * n is_prime[0] = False # IndexError when n = 0 is_prime[1] = False # IndexError when n = 0 or n = 1
Solution: Always check bounds before accessing array indices:
is_prime = [True] * n if n > 0: is_prime[0] = False if n > 1: is_prime[1] = False
2. Incorrect Range in Sieve Implementation
Another pitfall is using an incorrect range when marking composite numbers, which can lead to incomplete prime detection.
Problematic Code:
# Starting from i * i instead of i * 2
for j in range(i * i, n, i): # May miss some composites
is_prime[j] = False
While starting from i * i
is a valid optimization (since smaller multiples have already been marked), it requires careful handling of integer overflow for large values. Starting from i * 2
is safer and clearer.
Solution:
for j in range(i * 2, n, i):
is_prime[j] = False
3. Off-by-One Error in Finding Pairs
Forgetting to include n // 2
in the range when n
is even can cause missing valid pairs.
Problematic Code:
for x in range(2, n // 2): # Excludes n//2
y = n - x
# This misses the pair where x = y = n/2 when n is even
Solution:
for x in range(2, n // 2 + 1): # Includes n//2
y = n - x
4. Not Handling n < 2 Properly
When n < 2
, there cannot be any valid prime pairs since the smallest prime is 2.
Problematic Code:
def findPrimePairs(self, n: int) -> List[List[int]]:
is_prime = [True] * n # Creates empty array when n = 0
# Rest of the code...
Solution: Add an early return for invalid cases:
def findPrimePairs(self, n: int) -> List[List[int]]:
# No valid prime pairs possible for n < 4
if n < 4:
return []
is_prime = [True] * n
# Rest of the code...
5. Memory Inefficiency for Large n
Creating a boolean array of size n
can be memory-intensive for very large values of n
.
Alternative Approach for Memory Optimization: Instead of storing all primes, generate them on-the-fly or use a set to store only actual primes:
def findPrimePairs(self, n: int) -> List[List[int]]:
# Generate set of primes up to n
primes_set = set()
is_prime = [True] * n
# Sieve to identify primes
for i in range(2, n):
if is_prime[i]:
primes_set.add(i)
for j in range(i * 2, n, i):
is_prime[j] = False
# Find pairs using the set
result = []
for x in primes_set:
if x > n // 2:
break
y = n - x
if y in primes_set:
result.append([x, y])
return sorted(result) # Sort by x
Which algorithm is best for finding the shortest distance between two points in an unweighted graph?
Recommended Readings
Math for Technical Interviews How much math do I need to know for technical interviews The short answer is about high school level math Computer science is often associated with math and some universities even place their computer science department under the math faculty However the reality is that you
Coding Interview Patterns Your Personal Dijkstra's Algorithm to Landing Your Dream Job The goal of AlgoMonster is to help you get a job in the shortest amount of time possible in a data driven way We compiled datasets of tech interview problems and broke them down by patterns This way
Recursion Recursion is one of the most important concepts in computer science Simply speaking recursion is the process of a function calling itself Using a real life analogy imagine a scenario where you invite your friends to lunch https assets algo monster recursion jpg You first call Ben and ask
Want a Structured Path to Master System Design Too? Don’t Miss This!