Facebook Pixel

2081. Sum of k-Mirror Numbers

HardMathEnumeration
Leetcode Link

Problem Description

A k-mirror number is a positive integer without leading zeros that is a palindrome (reads the same forwards and backwards) in both base-10 and base-k representations.

For example:

  • 9 is a 2-mirror number because:

    • In base-10: 9 reads the same forwards and backwards
    • In base-2: 9 = 1001, which also reads the same forwards and backwards
  • 4 is NOT a 2-mirror number because:

    • In base-10: 4 reads the same forwards and backwards
    • In base-2: 4 = 100, which does NOT read the same forwards and backwards

Given two parameters:

  • k: the base to check alongside base-10
  • n: the count of k-mirror numbers needed

The task is to find the n smallest k-mirror numbers and return their sum.

The solution works by generating palindromes in base-10 and then checking if they are also palindromes when converted to base-k. It systematically generates base-10 palindromes by:

  1. Enumerating palindrome lengths starting from 1
  2. For each length l, generating the first half of potential palindromes
  3. Constructing complete palindromes by mirroring the first half (handling odd/even lengths differently)
  4. Checking if each generated base-10 palindrome is also a palindrome in base-k
  5. Collecting the first n such numbers and returning their sum
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

Intuition

The key insight is that checking all positive integers sequentially would be inefficient. Instead, we can be smarter by generating only base-10 palindromes first, then checking if they're also palindromes in base-k.

Why does this work? Because k-mirror numbers must be palindromes in base-10, we're guaranteed that every k-mirror number will be found in our generated base-10 palindromes. This dramatically reduces our search space.

To generate base-10 palindromes efficiently, we use a "half construction" technique. Any palindrome can be built by taking its first half and mirroring it. For example:

  • For even-length palindrome 1221: take first half 12, mirror it to get 21, combine to get 1221
  • For odd-length palindrome 12321: take first half 123, mirror all but the middle digit to get 21, combine to get 12321

By systematically generating palindromes this way (starting from length 1 and increasing), we ensure we get them in ascending order. This is crucial because we need the n smallest k-mirror numbers.

The approach becomes:

  1. Generate palindromes in ascending order by length
  2. For each length, generate all possible first halves
  3. Construct the full palindrome from each first half
  4. Check if it's also a palindrome in base-k
  5. Keep track until we find n such numbers

This method is much more efficient than brute force because we're only checking numbers that are already palindromes in base-10, eliminating the vast majority of numbers that could never be k-mirror numbers.

Learn more about Math patterns.

Solution Approach

The implementation follows a systematic approach to generate and validate k-mirror numbers:

1. Main Loop Structure

We use an infinite counter count(1) to iterate through palindrome lengths starting from 1. For each length l, we determine the range of values for the first half of potential palindromes:

  • Starting value: x = 10^((l-1)//2)
  • Ending value: y = 10^((l+1)//2)

For example:

  • Length 1: range is [1, 10)
  • Length 2: range is [1, 10)
  • Length 3: range is [10, 100)
  • Length 4: range is [10, 100)

2. Palindrome Construction

For each number i in the first half range, we construct the complete palindrome v:

  • Initialize v = i (this becomes the first half)
  • Determine what to mirror:
    • If length is even (l % 2 == 0): mirror the entire i
    • If length is odd: mirror i // 10 (exclude the middle digit from mirroring)
  • Build the second half by reversing digits:
    while j > 0:
        v = v * 10 + j % 10  # Append last digit of j to v
        j //= 10              # Remove last digit from j

3. Base-k Palindrome Check

The check function verifies if a number is a palindrome in base-k:

def check(x: int, k: int) -> bool:
    s = []
    while x:
        s.append(x % k)  # Extract digits in base-k
        x //= k
    return s == s[::-1]  # Check if palindrome

This converts the number to base-k representation and stores digits in a list, then checks if the list reads the same forwards and backwards.

4. Result Accumulation

When a k-mirror number is found:

  • Add it to the running sum ans
  • Decrement the counter n
  • When n reaches 0, return the accumulated sum

Example Walkthrough

For k=2, n=5, the algorithm would:

  1. Start with length 1: generate palindromes 1, 2, ..., 9
  2. Check each in base-2:
    • 11 in base-2 (palindrome ✓)
    • 311 in base-2 (palindrome ✓)
    • 5101 in base-2 (palindrome ✓)
    • 7111 in base-2 (palindrome ✓)
    • 91001 in base-2 (palindrome ✓)
  3. Found 5 k-mirror numbers, return their sum: 1 + 3 + 5 + 7 + 9 = 25

This approach efficiently finds k-mirror numbers by generating only base-10 palindromes and filtering those that are also palindromes in base-k, avoiding unnecessary checks on non-palindromic numbers.

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 find the first 3 k-mirror numbers where k=3, and calculate their sum.

Step 1: Generate palindromes of length 1

First half range for length 1: [1, 10)

  • Generate palindrome from i=1: Result is 1

    • Check if 1 is palindrome in base-3: 11 in base-3 ✓
    • Found 1st k-mirror number: 1
  • Generate palindrome from i=2: Result is 2

    • Check if 2 is palindrome in base-3: 22 in base-3 ✓
    • Found 2nd k-mirror number: 2
  • Generate palindrome from i=3: Result is 3

    • Check if 3 is palindrome in base-3: 310 in base-3 ✗ (not palindrome)
  • Generate palindrome from i=4: Result is 4

    • Check if 4 is palindrome in base-3: 411 in base-3 ✓
    • Found 3rd k-mirror number: 4

Result: We found our 3 k-mirror numbers: 1, 2, 4

Detailed construction for one palindrome (length 3 example):

If we had continued to length 3 looking for more numbers:

  • For i=10 (first value in range [10, 100)):
    • Start with v = 10
    • Since length is odd, mirror i // 10 = 1
    • Build palindrome: v = 10 * 10 + 1 = 101
    • Check 101 in base-3: 10110202 (palindrome ✓)

Base-3 conversion demonstration for 4:

4 ÷ 3 = 1 remainder 1  → rightmost digit is 1
1 ÷ 3 = 0 remainder 1  → next digit is 1
Result: 4 in base-3 = 11 (reads same forwards/backwards)

Final answer: Sum = 1 + 2 + 4 = 7

Solution Implementation

1from itertools import count
2
3class Solution:
4    def kMirror(self, k: int, n: int) -> int:
5        """
6        Find the sum of the first n k-mirror numbers.
7        A k-mirror number is a positive integer that is a palindrome in both base 10 and base k.
8      
9        Args:
10            k: The base to check for palindrome property (2 <= k <= 9)
11            n: The number of k-mirror numbers to find
12          
13        Returns:
14            The sum of the first n k-mirror numbers
15        """
16      
17        def is_palindrome_in_base_k(number: int, base: int) -> bool:
18            """
19            Check if a number is a palindrome when represented in base k.
20          
21            Args:
22                number: The number to check
23                base: The base for representation
24              
25            Returns:
26                True if the number is a palindrome in the given base, False otherwise
27            """
28            digits = []
29            temp = number
30          
31            # Convert number to base k representation
32            while temp > 0:
33                digits.append(temp % base)
34                temp //= base
35          
36            # Check if digits form a palindrome
37            return digits == digits[::-1]
38      
39        total_sum = 0
40      
41        # Iterate through palindrome lengths starting from 1
42        for palindrome_length in count(1):
43            # Calculate the range for the left half of the palindrome
44            # For odd length palindromes, we need fewer digits in the left half
45            left_half_start = 10 ** ((palindrome_length - 1) // 2)
46            left_half_end = 10 ** ((palindrome_length + 1) // 2)
47          
48            # Generate all palindromes of current length
49            for left_half in range(left_half_start, left_half_end):
50                palindrome = left_half
51              
52                # Determine what part to mirror based on odd/even length
53                # For even length: mirror all digits
54                # For odd length: mirror all but the middle digit
55                digits_to_mirror = left_half if palindrome_length % 2 == 0 else left_half // 10
56              
57                # Build the complete palindrome by appending reversed digits
58                while digits_to_mirror > 0:
59                    palindrome = palindrome * 10 + digits_to_mirror % 10
60                    digits_to_mirror //= 10
61              
62                # Check if this palindrome is also a palindrome in base k
63                if is_palindrome_in_base_k(palindrome, k):
64                    total_sum += palindrome
65                    n -= 1
66                  
67                    # Return when we've found n k-mirror numbers
68                    if n == 0:
69                        return total_sum
70
1class Solution {
2    /**
3     * Finds the sum of the first n k-mirror numbers.
4     * A k-mirror number is a positive integer that reads the same both in base-10 and base-k.
5     * 
6     * @param k The base to check for mirror property (2 <= k <= 9)
7     * @param n The number of k-mirror numbers to find
8     * @return The sum of the first n k-mirror numbers
9     */
10    public long kMirror(int k, int n) {
11        long sum = 0;
12      
13        // Iterate through palindromes of increasing length
14        for (int length = 1; ; length++) {
15            // Calculate the range for the left half of the palindrome
16            // For odd length palindromes, we need (length-1)/2 digits for the left part
17            // For even length palindromes, we need (length+1)/2 digits for the left part
18            int startRange = (int) Math.pow(10, (length - 1) / 2);
19            int endRange = (int) Math.pow(10, (length + 1) / 2);
20          
21            // Generate all palindromes of current length
22            for (int leftHalf = startRange; leftHalf < endRange; leftHalf++) {
23                // Build the palindrome in base-10
24                long palindrome = leftHalf;
25              
26                // Determine what to mirror based on odd/even length
27                // For odd length: mirror without the middle digit (divide by 10)
28                // For even length: mirror the entire left half
29                int toMirror = (length % 2 == 0) ? leftHalf : leftHalf / 10;
30              
31                // Append the mirrored digits to create the full palindrome
32                while (toMirror > 0) {
33                    palindrome = palindrome * 10 + toMirror % 10;
34                    toMirror /= 10;
35                }
36              
37                // Check if this base-10 palindrome is also a palindrome in base-k
38                if (isBaseKPalindrome(palindrome, k)) {
39                    sum += palindrome;
40                    n--;
41                  
42                    // Return when we've found n k-mirror numbers
43                    if (n == 0) {
44                        return sum;
45                    }
46                }
47            }
48        }
49    }
50  
51    /**
52     * Checks if a number is a palindrome when represented in base-k.
53     * 
54     * @param number The number to check
55     * @param base The base to convert the number to
56     * @return true if the number is a palindrome in the given base, false otherwise
57     */
58    private boolean isBaseKPalindrome(long number, int base) {
59        // Convert number to base-k representation and store digits
60        List<Integer> baseKDigits = new ArrayList<>();
61      
62        while (number > 0) {
63            baseKDigits.add((int) (number % base));
64            number /= base;
65        }
66      
67        // Check if the base-k representation is a palindrome
68        // Compare digits from both ends moving towards the center
69        int left = 0;
70        int right = baseKDigits.size() - 1;
71      
72        while (left < right) {
73            if (!baseKDigits.get(left).equals(baseKDigits.get(right))) {
74                return false;
75            }
76            left++;
77            right--;
78        }
79      
80        return true;
81    }
82}
83
1class Solution {
2public:
3    long long kMirror(int k, int n) {
4        long long sum = 0;
5      
6        // Iterate through palindrome lengths starting from 1
7        for (int length = 1;; ++length) {
8            // Calculate the range for the left half of the palindrome
9            // For odd length palindromes, we need ceil(length/2) digits
10            // For even length palindromes, we need length/2 digits
11            int startRange = pow(10, (length - 1) / 2);
12            int endRange = pow(10, (length + 1) / 2);
13          
14            // Generate all palindromes of current length
15            for (int leftHalf = startRange; leftHalf < endRange; ++leftHalf) {
16                // Build the palindrome in base 10
17                long long palindrome = leftHalf;
18              
19                // Determine what to mirror based on odd/even length
20                // For odd length: mirror everything except the middle digit
21                // For even length: mirror the entire left half
22                int mirrorPart = (length % 2 == 0) ? leftHalf : leftHalf / 10;
23              
24                // Append the reversed digits to form the palindrome
25                while (mirrorPart > 0) {
26                    palindrome = palindrome * 10 + mirrorPart % 10;
27                    mirrorPart /= 10;
28                }
29              
30                // Check if this number is also a palindrome in base k
31                if (isKBasePalindrome(palindrome, k)) {
32                    sum += palindrome;
33                    --n;
34                  
35                    // Return when we've found n k-mirror numbers
36                    if (n == 0) {
37                        return sum;
38                    }
39                }
40            }
41        }
42    }
43
44private:
45    // Check if a number is a palindrome when represented in base k
46    bool isKBasePalindrome(long long number, int base) {
47        // Convert number to base k representation
48        vector<int> digits;
49        while (number > 0) {
50            digits.push_back(number % base);
51            number /= base;
52        }
53      
54        // Check if the digits form a palindrome
55        int left = 0;
56        int right = digits.size() - 1;
57        while (left < right) {
58            if (digits[left] != digits[right]) {
59                return false;
60            }
61            ++left;
62            --right;
63        }
64      
65        return true;
66    }
67};
68
1/**
2 * Finds the sum of the first n k-mirror numbers.
3 * A k-mirror number is a positive integer that is a palindrome in both base-10 and base-k.
4 * 
5 * @param k - The base to check for palindrome property (2 <= k <= 9)
6 * @param n - The number of k-mirror numbers to find
7 * @returns The sum of the first n k-mirror numbers
8 */
9function kMirror(k: number, n: number): number {
10    /**
11     * Checks if a number is a palindrome in base k
12     * 
13     * @param number - The number to check
14     * @param base - The base for palindrome checking
15     * @returns true if the number is a palindrome in the given base, false otherwise
16     */
17    function isBaseKPalindrome(number: number, base: number): boolean {
18        // Convert number to base-k representation
19        const baseKDigits: number[] = [];
20        while (number > 0) {
21            baseKDigits.push(number % base);
22            number = Math.floor(number / base);
23        }
24      
25        // Check if the base-k representation is a palindrome
26        let leftIndex = 0;
27        let rightIndex = baseKDigits.length - 1;
28      
29        while (leftIndex < rightIndex) {
30            if (baseKDigits[leftIndex] !== baseKDigits[rightIndex]) {
31                return false;
32            }
33            leftIndex++;
34            rightIndex--;
35        }
36      
37        return true;
38    }
39
40    let sum = 0;
41  
42    // Iterate through palindromes by length (number of digits)
43    for (let length = 1; ; length++) {
44        // Calculate the range for generating palindromes of current length
45        // startValue: first number with ceiling((length-1)/2) + 1 digits
46        const startValue = Math.pow(10, Math.floor((length - 1) / 2));
47        // endValue: first number with ceiling((length+1)/2) + 1 digits
48        const endValue = Math.pow(10, Math.floor((length + 1) / 2));
49      
50        // Generate all palindromes of current length
51        for (let halfNumber = startValue; halfNumber < endValue; halfNumber++) {
52            // Build the palindrome from halfNumber
53            let palindrome = halfNumber;
54          
55            // For odd length palindromes, skip the middle digit when mirroring
56            // For even length palindromes, mirror all digits
57            let mirrorPart = length % 2 === 0 ? halfNumber : Math.floor(halfNumber / 10);
58          
59            // Append the reversed digits to create the palindrome
60            while (mirrorPart > 0) {
61                palindrome = palindrome * 10 + (mirrorPart % 10);
62                mirrorPart = Math.floor(mirrorPart / 10);
63            }
64          
65            // Check if this base-10 palindrome is also a palindrome in base-k
66            if (isBaseKPalindrome(palindrome, k)) {
67                sum += palindrome;
68                n--;
69              
70                // Return when we've found n k-mirror numbers
71                if (n === 0) {
72                    return sum;
73                }
74            }
75        }
76    }
77}
78

Time and Space Complexity

The time complexity of this algorithm depends on finding n k-mirror numbers (numbers that are palindromes in both base 10 and base k).

For each length l of base-10 palindromes:

  • We iterate through 10^((l-1)/2) to 10^((l+1)/2) possible first halves, which is approximately 10^(l/2) iterations
  • For each candidate, we construct a palindrome in O(l) time
  • We check if it's a palindrome in base k using the check function, which takes O(log_k(v)) time where v is the palindrome value

Since we need to find exactly n k-mirror numbers and n ≤ 30, the actual number of iterations is bounded. In practice, we'll examine palindromes of increasing lengths until we find n valid k-mirror numbers. The worst-case involves checking many palindromes before finding the required n k-mirror numbers.

Time Complexity: O(n × 10^(l/2) × l) where l is the maximum length of palindromes needed to find n k-mirror numbers. Since n is at most 30, this is effectively bounded in practice.

Space Complexity: O(log_k(v)) for the list s used in the check function to store the base-k representation. Since we only use a constant amount of additional variables and the list s is recreated for each check, the space complexity is O(log_k(v)) where v is the current palindrome value being checked.

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

Common Pitfalls

1. Incorrect Palindrome Generation for Odd vs Even Lengths

Pitfall: A common mistake is incorrectly handling the middle digit when generating odd-length palindromes. Developers often mirror the entire left half for odd-length palindromes, which creates incorrect results.

Example of the mistake:

# WRONG: Always mirroring the entire left_half
digits_to_mirror = left_half  # This is incorrect for odd lengths!

For a 3-digit palindrome starting with 12, this would incorrectly generate 12221 (5 digits) instead of 121 (3 digits).

Solution:

# CORRECT: Exclude middle digit for odd-length palindromes
digits_to_mirror = left_half if palindrome_length % 2 == 0 else left_half // 10

2. Off-by-One Errors in Range Calculation

Pitfall: Incorrectly calculating the range for the left half can miss palindromes or generate invalid ones. A common error is using 10 ** (palindrome_length // 2) for both start and end calculations.

Example of the mistake:

# WRONG: This misses single-digit palindromes and has incorrect ranges
left_half_start = 10 ** (palindrome_length // 2)  # Would start at 10 for length 1!

Solution:

# CORRECT: Proper range calculation
left_half_start = 10 ** ((palindrome_length - 1) // 2)
left_half_end = 10 ** ((palindrome_length + 1) // 2)

3. Base Conversion Edge Cases

Pitfall: The base-k palindrome check might fail for edge cases like when the number is 0 or when not properly handling the digit extraction.

Example of the mistake:

# WRONG: Doesn't handle number = 0 correctly
def is_palindrome_in_base_k(number: int, base: int) -> bool:
    digits = []
    while number > 0:  # This loop never executes for number = 0
        digits.append(number % base)
        number //= base
    return digits == digits[::-1]  # Returns True for empty list!

Solution:

# CORRECT: Handle edge cases explicitly
def is_palindrome_in_base_k(number: int, base: int) -> bool:
    if number == 0:
        return True  # 0 is a palindrome in any base
    digits = []
    temp = number
    while temp > 0:
        digits.append(temp % base)
        temp //= base
    return digits == digits[::-1]

4. Performance Degradation with Large n

Pitfall: Not breaking out of the inner loop early when enough k-mirror numbers are found, leading to unnecessary palindrome generation.

Example of the mistake:

# WRONG: Continuing to generate palindromes even after finding n numbers
for left_half in range(left_half_start, left_half_end):
    # ... generate palindrome ...
    if is_palindrome_in_base_k(palindrome, k):
        total_sum += palindrome
        n -= 1
# Missing early termination!

Solution:

# CORRECT: Return immediately when n reaches 0
if is_palindrome_in_base_k(palindrome, k):
    total_sum += palindrome
    n -= 1
    if n == 0:
        return total_sum  # Early termination

5. Integer Overflow in Other Languages

Pitfall: While Python handles arbitrary precision integers, implementing this in languages like Java or C++ requires careful consideration of integer overflow when calculating palindromes or their sum.

Solution for other languages:

  • Use appropriate data types (long long in C++, long in Java)
  • Consider using BigInteger classes for very large values
  • Add overflow checks when multiplying by 10 or adding digits
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Tailor Your Study Plan:

In a binary min heap, the maximum element can be found in:


Recommended Readings

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

Load More