Given two integers n
and k
, return the kth
lexicographically smallest integer in the range [1, n]
.
Example 1:
Input: n = 13, k = 2 Output: 10 Explanation: The lexicographical order is [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9], so the second smallest number is 10.
Example 2:
Input: n = 1, k = 1 Output: 1
Constraints:
1 <= k <= n <= 109
When you get asked this question in a real-life environment, it will often be ambiguous (especially at FAANG). Make sure to ask these questions in that case:
The brute force method for finding the K-th smallest number lexicographically involves generating every number within a certain range as strings. We then sort these strings alphabetically, and the K-th entry in this sorted list is our answer. This is like making a complete dictionary of all possible numbers and finding the one at the K-th page.
Here's how the algorithm would work step-by-step:
def find_kth_smallest_lexicographical(maximum_number, k_value):
# Create a list of all numbers from 1 to maximum_number.
number_list = [str(number) for number in range(1, maximum_number + 1)]
# Sort the numbers lexicographically (as strings).
number_list.sort()
# Return the k_value-th element in the sorted list.
# Adjust index because lists are zero-indexed.
return int(number_list[k_value - 1])
To efficiently find the K-th smallest number in lexicographical order, we'll use a step-by-step counting process instead of generating all possible numbers. We cleverly navigate the number space to skip over large sections we know are too small to contain our target.
Here's how the algorithm would work step-by-step:
def find_kth_number(max_number, k_value):
current_number = 1
while k_value > 1:
# Calculate how many numbers have current_number as a prefix
numbers_with_prefix = count_numbers_with_prefix(
max_number, current_number
)
# Kth number is in the range starting from current_number
if numbers_with_prefix >= k_value:
current_number *= 10
k_value -= 1
# Kth number is not within this prefix
else:
k_value -= numbers_with_prefix
current_number += 1
# Adjust if current_number exceeds max_number
while current_number % 10 == 0:
current_number //= 10
return current_number
def count_numbers_with_prefix(max_number, prefix):
next_prefix = prefix + 1
step = 0
# Count how many numbers between prefix and next prefix
while prefix <= max_number:
step += min(max_number + 1, next_prefix) - prefix
prefix *= 10
next_prefix *= 10
return step
Case | How to Handle |
---|---|
n or k is zero | If n or k is zero, return 0 as there are no numbers or we're asking for the zeroth smallest. |
k is greater than n | If k > n, return -1 (or an appropriate error value) since the kth lexicographical number cannot exist. |
n is a single digit number | Handle the case where n is a single-digit number; the k-th smallest number is simply k if k <= n. |
k is 1 | If k is 1, the result is always 1. |
k is close to n | Consider performance implications of reaching close to n using increments; a jump might be faster in some sections. |
Integer overflow when calculating steps (number of children) | Use long data type for calculations to avoid potential integer overflow during step calculation. |
Very large n | For very large 'n', the number of steps might also be extremely large, so handling of potentially large values is needed. |
k is a power of 10 | When k is a power of 10, the resulting lexicographical number may be different than initially projected. |