479. Largest Palindrome Product
Problem Description
You need to find the largest palindromic number that can be formed by multiplying two n-digit integers together.
A palindrome is a number that reads the same forwards and backwards (like 9009 or 12321).
Given an integer n
representing the number of digits, you should:
- Consider all possible products of two n-digit numbers
- Find which of these products are palindromes
- Return the largest such palindrome
Since the result can be extremely large, return the answer modulo 1337.
For example:
- If
n = 2
, the two-digit numbers range from 10 to 99 - The largest palindrome product would be 99 × 91 = 9009
- So you would return 9009 % 1337 = 987
The challenge is to efficiently find this largest palindrome without checking every possible product, as that would be computationally expensive for larger values of n
.
Intuition
The key insight is that we can construct palindromes directly rather than checking every possible product. Since we want the largest palindrome, we should start from the largest possible palindrome and work our way down.
For n-digit numbers, the maximum value is 10^n - 1
(like 99 for n=2, 999 for n=3). The largest possible product would be (10^n - 1) × (10^n - 1)
, which gives us an upper bound for our palindrome.
The clever approach is to build palindromes by taking the first half and mirroring it. For example, if we start with 99, we can create the palindrome 9999. If that doesn't work, try 98 → 9889, then 97 → 9779, and so on.
Here's the process:
- Start with the largest n-digit number as the first half (
a
) - Create a palindrome by appending the reverse of
a
to itself (so 99 becomes 9999) - Check if this palindrome can be expressed as a product of two n-digit numbers
- If yes, we found our answer; if no, decrease
a
and try again
To check if a palindrome x
is a valid product, we start from the largest n-digit number t
and check if x
is divisible by t
. We only need to check values of t
where t × t >= x
(since if t × t < x
, then t
multiplied by any n-digit number would be less than x
).
This approach is efficient because:
- We generate palindromes in descending order, so the first valid one is the largest
- We avoid checking millions of products by directly constructing palindrome candidates
- We stop as soon as we find a valid palindrome product
Solution Approach
The implementation follows the intuition by systematically generating palindromes and checking if they can be factored into two n-digit numbers.
Step 1: Calculate the maximum n-digit number
mx = 10**n - 1
This gives us 99 for n=2, 999 for n=3, etc.
Step 2: Generate palindromes in descending order
for a in range(mx, mx // 10, -1):
We iterate from the largest n-digit number down to the smallest n-digit number (mx // 10
is the lower bound).
Step 3: Construct the palindrome
b = x = a while b: x = x * 10 + b % 10 b //= 10
This creates a palindrome by:
- Starting with
x = a
(the first half) - Extracting digits from
b
(copy ofa
) usingb % 10
- Appending each digit to
x
by multiplyingx
by 10 and adding the digit - For example: if
a = 99
, thenx
becomes 99 → 990 → 9900 + 9 → 9909 → 99090 + 9 → 9999
Step 4: Check if the palindrome is a valid product
t = mx while t * t >= x: if x % t == 0: return x % 1337 t -= 1
Starting from the maximum n-digit number t
:
- Check if
t * t >= x
(ensuring the product can reach our palindrome) - If
x
is divisible byt
, thenx = t * (x/t)
where both factors could be n-digit numbers - If we find such a factor, return the palindrome modulo 1337
- Otherwise, decrease
t
and continue checking
Edge Case:
return 9
For n=1, the only single-digit palindrome product is 9 (3 × 3), which is handled as a special case.
The algorithm efficiently finds the answer by:
- Generating palindromes from largest to smallest
- For each palindrome, checking if it can be factored appropriately
- Returning immediately upon finding the first (and therefore largest) valid palindrome
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 = 2
(two-digit numbers from 10 to 99).
Step 1: Calculate maximum n-digit number
mx = 10^2 - 1 = 99
Step 2: Start generating palindromes from largest to smallest
First iteration with a = 99
:
- Create palindrome: Start with
x = 99
, then mirror itb = 99
- Extract last digit:
99 % 10 = 9
, append to x:x = 99 * 10 + 9 = 999
b = 99 // 10 = 9
- Extract last digit:
9 % 10 = 9
, append to x:x = 999 * 10 + 9 = 9999
b = 9 // 10 = 0
(done)
- Palindrome created:
x = 9999
Step 3: Check if 9999 can be factored into two 2-digit numbers
- Start with
t = 99
- Check: Is
99 * 99 = 9801 >= 9999
? No! So 9999 cannot be a product of two 2-digit numbers - Move to next palindrome
Second iteration with a = 98
:
- Create palindrome:
98 → 9889
- Check factorization starting from
t = 99
- Is
99 * 99 = 9801 >= 9889
? No!
- Is
- Move to next palindrome
Continue until a = 91
:
- Create palindrome:
91 → 9119
- Check factorization starting from
t = 99
- Is
99 * 99 = 9801 >= 9119
? Yes! - Is
9119 % 99 == 0
? No - Try
t = 98
: Is98 * 98 = 9604 >= 9119
? Yes! - Is
9119 % 98 == 0
? No - Continue checking...
- Eventually we'll find that 9119 doesn't factor nicely
- Is
When we reach a = 90
:
- Create palindrome:
90 → 9009
- Check factorization starting from
t = 99
- Is
99 * 99 = 9801 >= 9009
? Yes! - Is
9009 % 99 == 0
? Yes!9009 / 99 = 91
- Both 99 and 91 are 2-digit numbers ✓
- Is
Step 4: Return result
- Found largest palindrome: 9009
- Return
9009 % 1337 = 987
The algorithm efficiently found that 99 × 91 = 9009 is the largest palindrome product of two 2-digit numbers by:
- Generating palindromes in descending order (9999, 9889, 9779, ..., 9009)
- Checking each palindrome for valid factorization
- Stopping at the first valid palindrome found
Solution Implementation
1class Solution:
2 def largestPalindrome(self, n: int) -> int:
3 # Special case: for n=1, the largest palindrome product is 9 (3*3)
4 if n == 1:
5 return 9
6
7 # Find the maximum n-digit number
8 max_num = 10**n - 1
9
10 # Try to construct palindromes starting from the largest possible
11 # We iterate from max_num down to max_num//10 (minimum n-digit number)
12 for first_half in range(max_num, max_num // 10, -1):
13 # Construct a palindrome by mirroring the first half
14 # For example, if first_half = 123, palindrome = 123321
15 palindrome = first_half
16 temp = first_half
17
18 # Mirror the digits to create the second half of the palindrome
19 while temp > 0:
20 palindrome = palindrome * 10 + temp % 10
21 temp //= 10
22
23 # Check if this palindrome can be expressed as a product of two n-digit numbers
24 # Start from the largest possible divisor
25 divisor = max_num
26
27 # Only check divisors whose square is >= palindrome
28 # (if divisor^2 < palindrome, then palindrome/divisor > divisor,
29 # meaning we've already checked this pair)
30 while divisor * divisor >= palindrome:
31 if palindrome % divisor == 0:
32 # Found a valid factorization, return result modulo 1337
33 return palindrome % 1337
34 divisor -= 1
35
36 # This should not be reached for valid inputs
37 return 9
38
1class Solution {
2 public int largestPalindrome(int n) {
3 // Calculate the maximum n-digit number
4 int maxNumber = (int) Math.pow(10, n) - 1;
5
6 // Iterate from the maximum n-digit number down to find the largest palindrome
7 for (int firstHalf = maxNumber; firstHalf > maxNumber / 10; --firstHalf) {
8 // Create a palindrome by mirroring the first half
9 int tempNumber = firstHalf;
10 long palindrome = firstHalf;
11
12 // Append the reversed digits of firstHalf to create a palindrome
13 while (tempNumber != 0) {
14 palindrome = palindrome * 10 + tempNumber % 10;
15 tempNumber /= 10;
16 }
17
18 // Check if this palindrome can be expressed as a product of two n-digit numbers
19 for (long divisor = maxNumber; divisor * divisor >= palindrome; --divisor) {
20 // If palindrome is divisible by divisor, we found a valid product
21 if (palindrome % divisor == 0) {
22 // Return the palindrome modulo 1337
23 return (int) (palindrome % 1337);
24 }
25 }
26 }
27
28 // Special case: for n=1, the largest palindrome product is 9 (3*3=9)
29 return 9;
30 }
31}
32
1class Solution {
2public:
3 int largestPalindrome(int n) {
4 // Calculate the maximum n-digit number
5 int maxNDigitNum = pow(10, n) - 1;
6
7 // Iterate from the largest n-digit number down to find the largest palindrome
8 // We only need to check down to maxNDigitNum / 10 + 1 (smallest n-digit number)
9 for (int leftHalf = maxNDigitNum; leftHalf > maxNDigitNum / 10; --leftHalf) {
10 // Create a palindrome by mirroring the left half
11 int tempLeftHalf = leftHalf;
12 long palindrome = leftHalf;
13
14 // Mirror the digits of leftHalf to create the full palindrome
15 // For example: if leftHalf = 99, palindrome becomes 9999
16 while (tempLeftHalf > 0) {
17 palindrome = palindrome * 10 + tempLeftHalf % 10;
18 tempLeftHalf /= 10;
19 }
20
21 // Check if this palindrome can be formed by multiplying two n-digit numbers
22 // Start from the largest possible factor and work downward
23 for (long factor = maxNDigitNum; factor * factor >= palindrome; --factor) {
24 // If palindrome is divisible by factor, check if the quotient is valid
25 if (palindrome % factor == 0) {
26 // Found a valid palindrome product of two n-digit numbers
27 return palindrome % 1337;
28 }
29 }
30 }
31
32 // Special case: for n=1, the answer is 9 (3*3=9)
33 return 9;
34 }
35};
36
1function largestPalindrome(n: number): number {
2 // Calculate the maximum n-digit number
3 const maxNDigitNum: number = Math.pow(10, n) - 1;
4
5 // Iterate from the largest n-digit number down to find the largest palindrome
6 // We only need to check down to maxNDigitNum / 10 + 1 (smallest n-digit number)
7 for (let leftHalf = maxNDigitNum; leftHalf > Math.floor(maxNDigitNum / 10); leftHalf--) {
8 // Create a palindrome by mirroring the left half
9 let tempLeftHalf: number = leftHalf;
10 let palindrome: number = leftHalf;
11
12 // Mirror the digits of leftHalf to create the full palindrome
13 // For example: if leftHalf = 99, palindrome becomes 9999
14 while (tempLeftHalf > 0) {
15 palindrome = palindrome * 10 + tempLeftHalf % 10;
16 tempLeftHalf = Math.floor(tempLeftHalf / 10);
17 }
18
19 // Check if this palindrome can be formed by multiplying two n-digit numbers
20 // Start from the largest possible factor and work downward
21 for (let factor = maxNDigitNum; factor * factor >= palindrome; factor--) {
22 // If palindrome is divisible by factor, check if the quotient is valid
23 if (palindrome % factor === 0) {
24 // Found a valid palindrome product of two n-digit numbers
25 return palindrome % 1337;
26 }
27 }
28 }
29
30 // Special case: for n=1, the answer is 9 (3*3=9)
31 return 9;
32}
33
Time and Space Complexity
Time Complexity: O(10^n * 10^(n/2))
which simplifies to O(10^(3n/2))
The analysis breaks down as follows:
- The outer loop iterates from
mx
tomx // 10
, which is approximately10^n - 10^(n-1) ≈ 9 * 10^(n-1)
iterations, simplified toO(10^n)
iterations - For each value of
a
, we construct a palindrome by reversinga
and appending it, which takesO(n)
time (sincea
has at mostn
digits) - The inner while loop checks divisors from
mx
down to√x
, wherex
is the palindrome formed. Sincex ≈ 10^(2n)
, we check approximately10^n - 10^(n/2) ≈ O(10^n)
potential divisors in the worst case - Therefore, the total time complexity is
O(10^n) * O(10^n) = O(10^(2n))
for the nested loops, but since we're checking divisibility and the inner loop often terminates early when a divisor is found, the practical complexity is closer toO(10^(3n/2))
Space Complexity: O(1)
The space analysis:
- The algorithm uses only a constant number of variables:
mx
,a
,b
,x
, andt
- No additional data structures like arrays, lists, or recursion stacks are used
- All operations are performed in-place with primitive integer variables
- Therefore, the space complexity is constant
O(1)
Common Pitfalls
1. Integer Overflow for Large Values of n
When n
gets large (especially n ≥ 7), the palindrome numbers become massive and can exceed the typical integer limits in some programming languages. For instance, with n=8, we're dealing with 16-digit palindromes that can reach values near 10^16.
Solution: Python handles arbitrary precision integers natively, but in languages like Java or C++, you'd need to:
- Use
long long
in C++ orLong
in Java - Consider using modular arithmetic throughout if only the final modulo result is needed
- Implement custom big integer handling for very large values
2. Inefficient Palindrome Generation Leading to Timeout
A naive approach might generate all possible products first and then check for palindromes, which has O(10^(2n)) complexity. Even the optimized approach can be slow if not carefully implemented.
Solution:
- Generate palindromes directly rather than checking all products
- Start from the largest possible palindrome and work downward
- Use early termination: once a valid palindrome is found, immediately return it
- Optimize the divisor checking loop by only checking divisors where
divisor * divisor >= palindrome
3. Incorrect Palindrome Construction
A common mistake is incorrectly mirroring the digits. For example, attempting to use string concatenation or getting the digit extraction wrong:
# WRONG: This doesn't properly reverse the digits
palindrome = int(str(first_half) + str(first_half)) # Creates 123123, not 123321
# CORRECT: Properly extract and append digits in reverse
while temp > 0:
palindrome = palindrome * 10 + temp % 10
temp //= 10
Solution: Use the mathematical approach shown in the code that extracts digits using modulo 10 and integer division, building the palindrome digit by digit.
4. Missing the n=1 Edge Case
The algorithm assumes we're creating even-length palindromes by mirroring n-digit numbers. For n=1, this would create 2-digit palindromes (like 11, 22, etc.), but these aren't products of two 1-digit numbers.
Solution: Handle n=1 as a special case that returns 9 (which is 3 × 3).
5. Incorrect Bounds for Factor Checking
When checking if a palindrome can be factored into two n-digit numbers, both factors must be n-digit numbers. A common mistake is not ensuring both factors fall within the valid range.
# WRONG: Doesn't ensure the quotient is also an n-digit number if palindrome % divisor == 0: return palindrome % 1337 # BETTER: Could add verification that palindrome/divisor is also n-digits if palindrome % divisor == 0: quotient = palindrome // divisor if quotient <= max_num and quotient > max_num // 10: return palindrome % 1337
Solution: The current implementation relies on the fact that we start checking from the largest palindromes and the largest divisors, which implicitly ensures valid factorizations when found first.
Which data structure is used to implement recursion?
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!