Facebook Pixel

2217. Find Palindrome With Fixed Length

MediumArrayMath
LeetCode ↗

Problem Description

You are given an array of integers called queries and a positive integer intLength. Your task is to find specific palindromes based on these inputs.

For each value queries[i], you need to find the queries[i]-th smallest positive palindrome that has exactly intLength digits.

A palindrome is a number that reads the same forwards and backwards. For example, 121 and 1331 are palindromes. Important constraints:

  • Palindromes cannot have leading zeros (so 010 is not valid)
  • The palindromes must have exactly intLength digits

Your output should be an array answer where:

  • answer[i] contains the queries[i]-th smallest palindrome of length intLength
  • If the queries[i]-th palindrome doesn't exist (because there aren't that many palindromes of the given length), then answer[i] should be -1

For example, if intLength = 3, the smallest positive palindromes would be: 101, 111, 121, 131, 141, etc. If queries = [1, 2, 5], then:

  • The 1st smallest 3-digit palindrome is 101
  • The 2nd smallest 3-digit palindrome is 111
  • The 5th smallest 3-digit palindrome is 141
  • So the answer would be [101, 111, 141]
Quick Interview Experience
Help others by sharing your interview experience
Have you seen this problem before?

How We Pick the Algorithm

Why Math / Bit Manipulation?

This problem maps to Math / Bit Manipulation through a short path in the full flowchart.

Directsimulation?noMath orbittricks?yesMath / BitManipulation

The k-th palindrome of length L corresponds to a known half-value, then mirror it (skipping the middle digit for odd lengths).

Open in Flowchart

Intuition

The key insight is that we don't need to generate all palindromes to find the k-th one. Instead, we can directly compute it by understanding the structure of palindromes.

For a palindrome of length intLength, we only need to determine the first half of the digits (including the middle digit if the length is odd). The second half is just a mirror of the first half. This observation drastically simplifies our problem.

Consider palindromes of different lengths:

  • Length 3: 101, 111, 121, ... (determined by first 2 digits: 10, 11, 12, ...)
  • Length 4: 1001, 1111, 1221, ... (determined by first 2 digits: 10, 11, 12, ...)
  • Length 5: 10001, 10101, 10201, ... (determined by first 3 digits: 100, 101, 102, ...)

We notice that:

  1. The number of digits we need to determine is (intLength + 1) // 2
  2. These determining digits form a sequence starting from 10^(l-1) where l is the number of digits to determine
  3. The k-th palindrome corresponds to the k-th number in this sequence

For example, with intLength = 5:

  • We need to determine l = (5 + 1) // 2 = 3 digits
  • The sequence starts at 100 (which gives palindrome 10001)
  • The 2nd palindrome comes from 101 (giving 10101)
  • The 3rd palindrome comes from 102 (giving 10201)

To construct the full palindrome from the first half:

  • Take the first half digits
  • For the second half, reverse the first half
  • If intLength is odd, skip the middle digit when reversing (since it's already included)

The range of valid first-half values is from 10^(l-1) to 10^l - 1. If our query asks for a palindrome beyond this range, we return -1.

Pattern Learn more about Math patterns.

New to patterns?Most interview problems reduce to a handful of patterns. This video covers the main eight.

Solution Approach

Let's walk through the implementation step by step:

  1. Calculate the length of the first half:

    l = (intLength + 1) >> 1

    This uses right shift (>> 1) which is equivalent to dividing by 2. For a palindrome of length intLength, we need l digits to determine the entire palindrome.

  2. Determine the valid range for the first half:

    start, end = 10 ** (l - 1), 10**l - 1
    • start: The smallest l-digit number (e.g., 100 for 3 digits)
    • end: The largest l-digit number (e.g., 999 for 3 digits)

    These bounds ensure we don't have leading zeros and stay within the valid range.

  3. Process each query:

    for q in queries:
        v = start + q - 1

    For the q-th palindrome, we calculate the corresponding first half value v. Since start is the 1st palindrome's first half, we add q - 1 to get the q-th one.

  4. Check validity:

    if v > end:
        ans.append(-1)
        continue

    If v exceeds our upper bound, the q-th palindrome doesn't exist for this length.

  5. Construct the palindrome:

    s = str(v)
    s += s[::-1][intLength % 2 :]
    • Convert the first half v to string
    • Reverse the string with s[::-1]
    • If intLength is odd (intLength % 2 = 1), skip the first character of the reversed string (the middle digit) using slice [1:]
    • If intLength is even (intLength % 2 = 0), use the entire reversed string with slice [0:]
    • Concatenate to form the complete palindrome
  6. Convert and store result:

    ans.append(int(s))

    Convert the palindrome string back to integer and add to results.

Example walkthrough for intLength = 5, queries = [2]:

  • l = (5 + 1) >> 1 = 3
  • start = 100, end = 999
  • For query 2: v = 100 + 2 - 1 = 101
  • s = "101"
  • Reverse and skip middle: "101"[::-1][1:] = "01"
  • Final palindrome: "101" + "01" = "10101"
  • Result: 10101

Example Walkthrough

Let's walk through a concrete example with intLength = 4 and queries = [1, 3, 7].

Step 1: Determine the first half length

  • Since we need 4-digit palindromes, we calculate: l = (4 + 1) // 2 = 2
  • We only need to determine the first 2 digits

Step 2: Find the valid range

  • start = 10^(2-1) = 10 (smallest 2-digit number)
  • end = 10^2 - 1 = 99 (largest 2-digit number)
  • So our first-half values can range from 10 to 99

Step 3: Process each query

Query 1 (find 1st palindrome):

  • Calculate first half: v = 10 + 1 - 1 = 10
  • Check validity: 10 ≤ 99
  • Construct palindrome:
    • First half: "10"
    • Reverse: "01"
    • Since intLength is even (4 % 2 = 0), use entire reversed string
    • Result: "10" + "01" = "1001"
  • Answer: 1001

Query 3 (find 3rd palindrome):

  • Calculate first half: v = 10 + 3 - 1 = 12
  • Check validity: 12 ≤ 99
  • Construct palindrome:
    • First half: "12"
    • Reverse: "21"
    • Use entire reversed string (even length)
    • Result: "12" + "21" = "1221"
  • Answer: 1221

Query 7 (find 7th palindrome):

  • Calculate first half: v = 10 + 7 - 1 = 16
  • Check validity: 16 ≤ 99
  • Construct palindrome:
    • First half: "16"
    • Reverse: "61"
    • Result: "16" + "61" = "1661"
  • Answer: 1661

Final Result: [1001, 1221, 1661]

This demonstrates how we can directly compute the k-th palindrome without generating all preceding ones. The pattern becomes clear: for 4-digit palindromes, we have:

  • 1st: 10→1001
  • 2nd: 11→1111
  • 3rd: 12→1221
  • ...and so on

For an odd-length example with intLength = 3 and queries = [2]:

  • l = (3 + 1) // 2 = 2
  • First half value: v = 10 + 2 - 1 = 11
  • Construct: "11" + "11"[::-1][1:] = "11" + "1" = "111"
  • The middle digit (second '1') is shared, not duplicated

Solution Implementation

1class Solution:
2    def kthPalindrome(self, queries: List[int], intLength: int) -> List[int]:
3        # Calculate the length of the first half of the palindrome
4        # For odd length palindromes, we include the middle digit in the first half
5        half_length = (intLength + 1) >> 1  # Equivalent to (intLength + 1) // 2
6      
7        # Define the range of possible values for the first half
8        # The smallest first half starts with 1 (e.g., 10, 100, 1000...)
9        min_half = 10 ** (half_length - 1)
10        # The largest first half is all 9s (e.g., 99, 999, 9999...)
11        max_half = 10 ** half_length - 1
12      
13        result = []
14      
15        for query in queries:
16            # Calculate the first half value for the k-th palindrome
17            # query is 1-indexed, so we add (query - 1) to min_half
18            first_half_value = min_half + query - 1
19          
20            # Check if the requested palindrome exists
21            if first_half_value > max_half:
22                result.append(-1)
23                continue
24          
25            # Convert the first half to string for manipulation
26            first_half_str = str(first_half_value)
27          
28            # Build the palindrome by appending the reversed first half
29            # For odd length palindromes, skip the middle digit when reversing
30            # intLength % 2 gives 1 for odd lengths, 0 for even lengths
31            palindrome_str = first_half_str + first_half_str[::-1][intLength % 2:]
32          
33            # Convert back to integer and add to result
34            result.append(int(palindrome_str))
35      
36        return result
37
1class Solution {
2    public long[] kthPalindrome(int[] queries, int intLength) {
3        int queryCount = queries.length;
4        long[] result = new long[queryCount];
5      
6        // Calculate the length of the first half of the palindrome
7        // For odd length palindromes, we include the middle digit
8        int halfLength = (intLength + 1) >> 1;  // Equivalent to (intLength + 1) / 2
9      
10        // Calculate the range of valid first halves
11        long minHalf = (long) Math.pow(10, halfLength - 1);  // Smallest n-digit number
12        long maxHalf = (long) Math.pow(10, halfLength) - 1;  // Largest n-digit number
13      
14        // Process each query
15        for (int i = 0; i < queryCount; ++i) {
16            // Calculate the first half value for the k-th palindrome
17            // queries[i] is 1-indexed, so we subtract 1
18            long firstHalf = minHalf + queries[i] - 1;
19          
20            // Check if the requested palindrome exists
21            if (firstHalf > maxHalf) {
22                result[i] = -1;
23                continue;
24            }
25          
26            // Convert the first half to string
27            String halfString = "" + firstHalf;
28          
29            // Build the complete palindrome by appending the reversed half
30            // For odd length palindromes, skip the middle digit when reversing
31            String reversedPart = new StringBuilder(halfString)
32                .reverse()
33                .substring(intLength % 2);  // Skip first char if odd length
34          
35            // Combine both parts to form the complete palindrome
36            String palindrome = halfString + reversedPart;
37          
38            // Convert the palindrome string to long and store in result
39            result[i] = Long.parseLong(palindrome);
40        }
41      
42        return result;
43    }
44}
45
1class Solution {
2public:
3    vector<long long> kthPalindrome(vector<int>& queries, int intLength) {
4        // Calculate the length of the first half of the palindrome
5        // For odd length palindromes, we include the middle digit in the first half
6        int halfLength = (intLength + 1) >> 1;  // Equivalent to (intLength + 1) / 2
7      
8        // Calculate the range of possible values for the first half
9        // e.g., for halfLength = 3: start = 100, end = 999
10        long long startValue = pow(10, halfLength - 1);
11        long long endValue = pow(10, halfLength) - 1;
12      
13        vector<long long> result;
14      
15        // Process each query
16        for (int& query : queries) {
17            // Calculate the value of the first half for the k-th palindrome
18            // query is 1-indexed, so we subtract 1 to get 0-indexed position
19            long long firstHalfValue = startValue + query - 1;
20          
21            // Check if the requested palindrome exists
22            if (firstHalfValue > endValue) {
23                result.push_back(-1);
24                continue;
25            }
26          
27            // Convert the first half to string for manipulation
28            string firstHalf = to_string(firstHalfValue);
29          
30            // Create a copy for reversing
31            string reversedHalf = firstHalf;
32            reverse(reversedHalf.begin(), reversedHalf.end());
33          
34            // Build the complete palindrome
35            // For odd length: skip the middle digit when appending (already in firstHalf)
36            // For even length: append the entire reversed string
37            firstHalf += reversedHalf.substr(intLength % 2);
38          
39            // Convert the palindrome string back to long long and add to result
40            result.push_back(stoll(firstHalf));
41        }
42      
43        return result;
44    }
45};
46
1/**
2 * Finds the k-th palindrome number with a specific length for each query
3 * @param queries - Array of k values representing the k-th palindrome to find
4 * @param intLength - The desired length of palindrome numbers
5 * @returns Array of palindrome numbers corresponding to each query, or -1 if not exists
6 */
7function kthPalindrome(queries: number[], intLength: number): number[] {
8    // Determine if the palindrome length is odd
9    const isOddLength = intLength % 2 === 1;
10  
11    // Calculate the number of digits in the first half of the palindrome
12    // For odd length, we include the middle digit in the first half
13    const halfLength = Math.floor(intLength / 2) + (isOddLength ? 1 : 0);
14  
15    // Calculate the smallest number that forms the first half of palindrome
16    // e.g., for length 4 or 5, starts from 10; for length 6 or 7, starts from 100
17    const firstHalfStart = Math.pow(10, halfLength - 1);
18  
19    // Calculate the maximum number of palindromes possible with this length
20    // The first half can range from firstHalfStart to (firstHalfStart * 10 - 1)
21    const maxPalindromeCount = firstHalfStart * 9;
22  
23    // Process each query to find the corresponding palindrome
24    return queries.map(kthValue => {
25        // Check if the requested k-th palindrome exists
26        if (kthValue > maxPalindromeCount) {
27            return -1;
28        }
29      
30        // Calculate the first half of the k-th palindrome
31        const firstHalf = firstHalfStart + kthValue - 1;
32      
33        // Convert first half to string for manipulation
34        const firstHalfString = firstHalf.toString();
35      
36        // Create the second half by reversing the first half
37        // For odd length palindromes, skip the middle digit when creating the second half
38        const secondHalfString = firstHalfString
39            .split('')
40            .reverse()
41            .slice(isOddLength ? 1 : 0)
42            .join('');
43      
44        // Combine first half and second half to form the complete palindrome
45        const palindrome = Number(firstHalfString + secondHalfString);
46      
47        return palindrome;
48    });
49}
50

Time and Space Complexity

Time Complexity: O(m * l) where m is the length of queries and l is the length of intLength.

  • The algorithm calculates l = (intLength + 1) >> 1, which is O(1).
  • Computing start and end using exponentiation 10 ** (l - 1) and 10**l - 1 takes O(l) time each.
  • The main loop iterates through each query in queries, which runs m times.
  • Inside each iteration:
    • Computing v = start + q - 1 is O(1).
    • Comparison v > end is O(1).
    • Converting v to string takes O(l) time (since v has approximately l digits).
    • String reversal s[::-1] takes O(l) time.
    • String slicing s[::-1][intLength % 2:] takes O(l) time in the worst case.
    • String concatenation takes O(l) time.
    • Converting the final string back to integer takes O(intLength) time.
  • Since each iteration performs O(l) operations and we have m iterations, the total time complexity is O(m * l).

Space Complexity: O(m * intLength)

  • Variables l, start, and end use O(1) space.
  • The ans list stores up to m integers, where each integer can have up to intLength digits, requiring O(m * intLength) space.
  • Within each iteration:
    • String s uses O(l) space.
    • The reversed and sliced string uses O(l) space temporarily.
    • The concatenated palindrome string uses O(intLength) space.
  • The dominant space usage is the ans list containing all results, giving us O(m * intLength) space complexity.

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

Common Pitfalls

1. Off-by-One Error in Query Indexing

A frequent mistake is forgetting that queries are 1-indexed while our calculation is 0-indexed. Developers might write:

# WRONG: Missing the -1 adjustment
first_half_value = min_half + query

This would give us the (k+1)-th palindrome instead of the k-th palindrome.

Solution: Always remember to subtract 1 from the query:

first_half_value = min_half + query - 1

2. Incorrect Handling of Odd vs Even Length Palindromes

When constructing the palindrome, it's easy to confuse when to skip the middle character. A common error:

# WRONG: Using wrong condition for slicing
palindrome_str = first_half_str + first_half_str[::-1][1:]  # Always skips first char
# or
palindrome_str = first_half_str + first_half_str[::-1][(intLength + 1) % 2:]  # Wrong formula

Solution: Use intLength % 2 for the slice start:

  • For odd lengths (e.g., 5): intLength % 2 = 1, skip the middle digit
  • For even lengths (e.g., 4): intLength % 2 = 0, use all digits
palindrome_str = first_half_str + first_half_str[::-1][intLength % 2:]

3. Integer Division vs Bit Shift Confusion

While (intLength + 1) >> 1 and (intLength + 1) // 2 are equivalent for positive integers, using regular division / instead of integer division // causes issues:

# WRONG: Regular division returns float
half_length = (intLength + 1) / 2  # Returns 2.5 for intLength=4
min_half = 10 ** (half_length - 1)  # 10 ** 1.5 gives wrong result

Solution: Use integer division or bit shift:

half_length = (intLength + 1) // 2  # or (intLength + 1) >> 1

4. Boundary Check After Construction

Some might check if the palindrome is valid after constructing it:

# INEFFICIENT: Constructing palindrome before checking validity
first_half_value = min_half + query - 1
palindrome_str = str(first_half_value) + str(first_half_value)[::-1][intLength % 2:]
if len(palindrome_str) > intLength:  # Wrong check
    result.append(-1)

Solution: Check boundaries before construction to avoid unnecessary work:

if first_half_value > max_half:
    result.append(-1)
    continue
# Only construct palindrome if valid

5. Forgetting Edge Cases for Single-Digit Palindromes

When intLength = 1, the logic still works but might be confusing:

  • half_length = 1
  • min_half = 1, max_half = 9
  • The slice [intLength % 2:] becomes [1:] which correctly gives an empty string

However, some might try to handle this as a special case unnecessarily, adding complexity and potential bugs.

Solution: Trust the general formula - it handles all cases including intLength = 1 correctly without special casing.

Ready to land your dream job?

Unlock your dream job with a 5-minute quiz for a personalized study roadmap!

Get My Roadmap
Discover Your Strengths and Weaknesses: Take Our 5-Minute Quiz to Get a Personalized Study Roadmap:

Depth first search is equivalent to which of the tree traversal order?


Recommended Readings

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

Load More