2217. Find Palindrome With Fixed Length
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 thequeries[i]
-th smallest palindrome of lengthintLength
- If the
queries[i]
-th palindrome doesn't exist (because there aren't that many palindromes of the given length), thenanswer[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]
The solution leverages the fact that for a palindrome, you only need to determine the first half of the digits (rounding up), and the second half mirrors the first half. This significantly reduces the search space.
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:
- The number of digits we need to determine is
(intLength + 1) // 2
- These determining digits form a sequence starting from
10^(l-1)
wherel
is the number of digits to determine - 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 palindrome10001
) - The 2nd palindrome comes from
101
(giving10101
) - The 3rd palindrome comes from
102
(giving10201
)
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
.
Learn more about Math patterns.
Solution Approach
Let's walk through the implementation step by step:
-
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 lengthintLength
, we needl
digits to determine the entire palindrome. -
Determine the valid range for the first half:
start, end = 10 ** (l - 1), 10**l - 1
start
: The smallestl
-digit number (e.g.,100
for 3 digits)end
: The largestl
-digit number (e.g.,999
for 3 digits)
These bounds ensure we don't have leading zeros and stay within the valid range.
-
Process each query:
for q in queries: v = start + q - 1
For the q-th palindrome, we calculate the corresponding first half value
v
. Sincestart
is the 1st palindrome's first half, we addq - 1
to get the q-th one. -
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. -
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
- Convert the first half
-
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
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 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"
- First half:
- 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"
- First half:
- 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"
- First half:
- 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 isO(1)
. - Computing
start
andend
using exponentiation10 ** (l - 1)
and10**l - 1
takesO(l)
time each. - The main loop iterates through each query in queries, which runs
m
times. - Inside each iteration:
- Computing
v = start + q - 1
isO(1)
. - Comparison
v > end
isO(1)
. - Converting
v
to string takesO(l)
time (sincev
has approximatelyl
digits). - String reversal
s[::-1]
takesO(l)
time. - String slicing
s[::-1][intLength % 2:]
takesO(l)
time in the worst case. - String concatenation takes
O(l)
time. - Converting the final string back to integer takes
O(intLength)
time.
- Computing
- Since each iteration performs
O(l)
operations and we havem
iterations, the total time complexity isO(m * l)
.
Space Complexity: O(m * intLength)
- Variables
l
,start
, andend
useO(1)
space. - The
ans
list stores up tom
integers, where each integer can have up tointLength
digits, requiringO(m * intLength)
space. - Within each iteration:
- String
s
usesO(l)
space. - The reversed and sliced string uses
O(l)
space temporarily. - The concatenated palindrome string uses
O(intLength)
space.
- String
- The dominant space usage is the
ans
list containing all results, giving usO(m * intLength)
space complexity.
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.
Which of the following uses divide and conquer strategy?
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!