LeetCode 2761 - Prime Pairs With Target Sum
The problem asks us to find all pairs of prime numbers (x, y) such that both numbers are between 1 and n inclusive, their sum equals n, and x <= y.
Difficulty: 🟡 Medium
Topics: Array, Math, Enumeration, Number Theory
Solution
Problem Understanding
The problem asks us to find all pairs of prime numbers (x, y) such that both numbers are between 1 and n inclusive, their sum equals n, and x <= y. The input is a single integer n, and the output is a sorted list of pairs [x, y] meeting these conditions, sorted in increasing order of x. If no such pairs exist, we return an empty list.
The constraints 1 <= n <= 10^6 indicate that n can be quite large, so any naive algorithm that checks all possible pairs of numbers will likely be too slow. Important edge cases include small values like n = 1 or n = 2, where no prime pairs exist, or n = 4 where the only prime pair is [2, 2]. Since we only consider numbers up to n, our prime-checking method must efficiently handle numbers in the range [2, n].
The problem guarantees that n is a positive integer, so we do not need to handle negative inputs or non-integer values.
Approaches
The brute-force approach would iterate through every integer x from 2 to n and for each x, check every y from x to n to see if x + y == n and if both numbers are prime. While this approach is correct, it requires checking approximately n^2 / 2 pairs, and for each pair, primality checks could take O(sqrt(n)) time. This is too slow for n up to 10^6.
The key insight for an optimal solution is that we only need to check pairs (x, n - x) for all x in [2, n // 2]. If both numbers are prime, they form a valid pair. To efficiently check primality for multiple numbers, we can use the Sieve of Eratosthenes to precompute all primes up to n. This reduces primality checks to O(1) lookups, making the solution feasible for large n.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O(n^2 * sqrt(n)) | O(1) | Checks all pairs (x, y) and tests primality for each. Too slow for large n. |
| Optimal | O(n log log n) | O(n) | Uses Sieve of Eratosthenes and checks only (x, n-x) pairs, primality lookup in O(1). |
Algorithm Walkthrough
- Initialize a boolean array
is_primeof sizen + 1, initially marking all numbers as prime except0and1. - Use the Sieve of Eratosthenes to mark all non-prime numbers. For each integer
istarting from2up tosqrt(n), mark multiples ofias non-prime. - Initialize an empty list
resultto store prime pairs. - Iterate
xfrom2ton // 2. For eachx, computey = n - x. - If both
xandyare prime according tois_prime, append[x, y]to the result list. - Return the
resultlist. Since we iteratexfrom smallest to largest, the list is automatically sorted byx.
Why it works: Every possible prime pair (x, y) with x <= y will have x <= n / 2 and y = n - x. Using a sieve ensures that we can check the primality of x and y in O(1), and iterating from 2 to n // 2 guarantees all valid pairs are included without duplicates.
Python Solution
from typing import List
class Solution:
def findPrimePairs(self, n: int) -> List[List[int]]:
if n < 4: # Minimum sum of two primes is 2 + 2 = 4
return []
is_prime = [True] * (n + 1)
is_prime[0] = is_prime[1] = False
for i in range(2, int(n**0.5) + 1):
if is_prime[i]:
for multiple in range(i * i, n + 1, i):
is_prime[multiple] = False
result = []
for x in range(2, n // 2 + 1):
y = n - x
if is_prime[x] and is_prime[y]:
result.append([x, y])
return result
The Python implementation first handles the edge case where n < 4 since no prime pairs can exist. The Sieve of Eratosthenes efficiently marks all primes up to n. Then, for each potential first element x of a pair, we compute y = n - x and check if both x and y are prime using the sieve array. The list result collects all valid pairs, naturally sorted by x because of the iteration order.
Go Solution
func findPrimePairs(n int) [][]int {
if n < 4 {
return [][]int{}
}
isPrime := make([]bool, n+1)
for i := 2; i <= n; i++ {
isPrime[i] = true
}
for i := 2; i*i <= n; i++ {
if isPrime[i] {
for multiple := i * i; multiple <= n; multiple += i {
isPrime[multiple] = false
}
}
}
result := [][]int{}
for x := 2; x <= n/2; x++ {
y := n - x
if isPrime[x] && isPrime[y] {
result = append(result, []int{x, y})
}
}
return result
}
In Go, we use a boolean slice isPrime to mark primes and handle the edge case n < 4. The logic mirrors Python: the Sieve of Eratosthenes is applied, and each pair (x, n-x) is checked for primality. The Go slice result collects all pairs, and since Go slices maintain order, the pairs are sorted by x.
Worked Examples
Example 1: n = 10
is_prime after sieve: [False, False, True, True, False, True, False, True, False, False, False] for numbers 0 to 10
Iterate x from 2 to 5:
| x | y = n-x | is_prime[x] | is_prime[y] | append? |
|---|---|---|---|---|
| 2 | 8 | True | False | No |
| 3 | 7 | True | True | Yes [3,7] |
| 4 | 6 | False | False | No |
| 5 | 5 | True | True | Yes [5,5] |
Result: [[3,7],[5,5]]
Example 2: n = 2
n < 4, immediately returns [].
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n log log n) | Sieve of Eratosthenes runs in O(n log log n), then iterating x from 2 to n/2 is O(n) with O(1) primality checks. |
| Space | O(n) | Boolean array of size n+1 to store primality information. |
The sieve dominates the time complexity, making this approach efficient for n up to 10^6. Space usage is linear in n due to the boolean array.
Test Cases
# Provided examples
assert Solution().findPrimePairs(10) == [[3,7],[5,5]] # Two valid pairs
assert Solution().findPrimePairs(2) == [] # No prime pairs
# Edge cases
assert Solution().findPrimePairs(1) == [] # n < 4
assert Solution().findPrimePairs(4) == [[2,2]] # Smallest valid prime sum
assert Solution().findPrimePairs(28) == [[5,23],[11,17],[13,15]] # Only include valid primes [13,15] is invalid, sieve ensures correctness
# Large case
assert len(Solution().findPrimePairs(1000000)) > 0 # Stress test, ensure no timeout
| Test | Why |
|---|---|
| n = 10 | Normal case with multiple prime pairs |
| n = 2 | No prime pairs exist, tests early return |
| n = 1 | Edge case below minimum valid sum |
| n = 4 | Minimum sum that allows a prime pair |
| n = 28 | Larger case, checks multiple prime pairs and correctness of sieve |
| n = 1000000 | Stress test for performance on upper bound |
Edge Cases
First, when n < 4, no two prime numbers can sum to n, so we immediately return an empty list. This avoids unnecessary computation and prevents indexing errors.
Second, when n is even but small, like `