LeetCode 3890 - Integers With Multiple Sum of Two Cubes
The problem asks us to find all integers x less than or equal to a given integer n such that x can be expressed as the sum of cubes of two positive integers in at least two distinct ways.
Difficulty: 🟡 Medium
Topics: Hash Table, Sorting, Counting, Enumeration
Solution
Problem Understanding
The problem asks us to find all integers x less than or equal to a given integer n such that x can be expressed as the sum of cubes of two positive integers in at least two distinct ways. A “distinct way” means that the pairs (a, b) used to form x are different, where a and b are positive integers with a <= b.
In other words, we are searching for numbers that can be written as a^3 + b^3 = x for at least two distinct pairs (a, b). These numbers are sometimes known in number theory as taxicab numbers. The input n can be as large as 10^9, which rules out naive approaches that enumerate all possible sums blindly. The expected output is a sorted list of these "good integers".
Important edge cases include small values of n (e.g., less than the smallest taxicab number 1729), cases where n is exactly a taxicab number, and situations where multiple numbers satisfy the condition.
Approaches
Brute Force Approach
A brute-force approach would be to iterate over all pairs (a, b) such that a^3 + b^3 <= n, storing each sum in a map or dictionary to count how many distinct pairs produce that sum. After processing all pairs, we would collect the sums that appear more than once. This approach works because it directly follows the definition, but it is inefficient: if n is around 10^9, a and b can be up to roughly 1000 (1000^3 = 10^9), which makes the nested loop O(n^(2/3)). For the worst case, this results in roughly a million iterations-manageable but not optimal for repeated queries.
Optimal Approach
The key insight is that we only need sums of cubes of positive integers up to cbrt(n). Using a two-pointer approach over the sorted list of cubes can generate sums in ascending order efficiently. Alternatively, iterating a from 1 to cbrt(n) and for each a, iterating b from a upwards until a^3 + b^3 > n ensures that we do not compute unnecessary sums. We then use a hash map to track counts of sums. Any sum appearing more than once is a "good integer." This is far more efficient because it avoids storing all pairings in a list, reduces redundant calculations, and scales well with n up to 10^9.
| Approach | Time Complexity | Space Complexity | Notes |
|---|---|---|---|
| Brute Force | O((n^(1/3))^2) = O(n^(2/3)) | O(n^(2/3)) | Iterates all pairs (a, b) without pruning |
| Optimal | O(n^(2/3)) | O(n^(2/3)) | Uses hash map to count sums, prunes b loop early |
Algorithm Walkthrough
- Compute the integer cube root of
nto determine the maximum possible value foraandb. Let this bemax_val. - Initialize an empty hash map
sum_countto store the counts of sums of two cubes. - Loop
afrom 1 tomax_val. - For each
a, loopbfromatomax_val. Computesum_cube = a^3 + b^3. - If
sum_cubeexceedsn, break the inner loop, because further increasingbwill only increase the sum. - Otherwise, increment
sum_count[sum_cube]by 1. - After completing all loops, filter the keys in
sum_countthat have a count greater than 1. These are the "good integers." - Sort the resulting list in ascending order and return it.
Why it works: The invariant is that sum_count[x] correctly records the number of distinct (a, b) pairs that sum to x. By only including sums that appear more than once, we ensure we capture exactly those integers with multiple representations as sums of two cubes.
Python Solution
class Solution:
def findGoodIntegers(self, n: int) -> list[int]:
from collections import defaultdict
import math
max_val = int(n ** (1/3)) + 1
sum_count = defaultdict(int)
for a in range(1, max_val + 1):
a_cubed = a ** 3
if a_cubed > n:
break
for b in range(a, max_val + 1):
sum_cube = a_cubed + b ** 3
if sum_cube > n:
break
sum_count[sum_cube] += 1
result = [num for num, count in sum_count.items() if count > 1]
result.sort()
return result
The code first computes the largest integer whose cube is ≤ n. Then it iterates over all valid (a, b) pairs using nested loops, but the inner loop stops as soon as the sum exceeds n. Using defaultdict, we count occurrences of each sum. Finally, sums appearing more than once are collected and sorted.
Go Solution
func findGoodIntegers(n int) []int {
maxVal := 0
for i := 1; i*i*i <= n; i++ {
maxVal = i
}
sumCount := make(map[int]int)
for a := 1; a <= maxVal; a++ {
aCubed := a * a * a
if aCubed > n {
break
}
for b := a; b <= maxVal; b++ {
sumCube := aCubed + b*b*b
if sumCube > n {
break
}
sumCount[sumCube]++
}
}
result := []int{}
for num, count := range sumCount {
if count > 1 {
result = append(result, num)
}
}
// Sort the result
for i := 0; i < len(result)-1; i++ {
for j := i + 1; j < len(result); j++ {
if result[i] > result[j] {
result[i], result[j] = result[j], result[i]
}
}
}
return result
}
The Go version mirrors the Python logic. Maps are used for counting. Since Go does not have a built-in sorting for slices of integers without importing sort, a simple bubble sort is applied here for clarity. Using make(map[int]int) ensures we can count sums efficiently.
Worked Examples
Example 1: n = 4104
- Compute
max_val = int(cbrt(4104)) + 1 = 16. - Iterate
afrom 1 to 16 andbfromato 16. - Track sums:
| a | b | a³+b³ | sum_count |
|---|---|---|---|
| 1 | ... | ... | ... |
| 1 | 16 | 1+4096=4097 | 1 |
| 9 | 10 | 729+1000=1729 | 1 |
| 1 | ... | ... | ... |
| 9 | 10 | 729+1000=1729 | 2 |
Finally, sums with count > 1 are [1729, 4104].
Example 2: n = 578
max_val = int(cbrt(578)) + 1 = 9- All pairs
(a, b)produce sums less than 578. - No sum occurs more than once. Result is
[].
Complexity Analysis
| Measure | Complexity | Explanation |
|---|---|---|
| Time | O(n^(2/3)) | The outer loop runs up to cbrt(n), inner loop also up to cbrt(n). Hash map insertions are O(1). |
| Space | O(n^(2/3)) | Hash map stores sums generated from all (a, b) pairs, which is bounded by O(n^(2/3)). |
Even though worst-case time is O(n^(2/3)), the pruning in the inner loop ensures we do not perform unnecessary computations, making it efficient for n ≤ 10^9.
Test Cases
s = Solution()
# Provided examples
assert s.findGoodIntegers(4104) == [1729, 4104] # multiple representations
assert s.findGoodIntegers(578) == [] # no good integers
# Edge cases
assert s.findGoodIntegers(1) == [] # n smaller than smallest good integer
assert s.findGoodIntegers(1729) == [1729] # exactly first good integer
assert s.findGoodIntegers(5000) == [1729, 4104] # multiple good integers
# Larger n
assert s.findGoodIntegers(20000) == [1729, 4104, 13832] # next known taxicab numbers
| Test | Why |
|---|---|
| n = 4104 | Checks normal case with multiple good integers |
| n = 578 | Checks |