Given two integers n
and k
, return the k<sup>th</sup>
lexicographically smallest integer in the range [1, n]
. For example:
n = 13
and k = 2
, the lexicographical order is [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9]
, so the second smallest number is 10
. Return 10n = 1
and k = 1
, return 1.Write an efficient algorithm to solve this problem, considering that 1 <= k <= n <= 10^9
.
A naive approach would involve generating all numbers from 1 to n
, sorting them lexicographically (as strings), and then returning the k
th element. This is highly inefficient, especially for large values of n
.
def findKthNumber_brute_force(n: int, k: int) -> int:
nums = list(map(str, range(1, n + 1)))
nums.sort()
return int(nums[k - 1])
This approach fails for larger values of n, as we will get a timeout.
A more efficient approach involves traversing the lexicographical tree. We start from 1 and explore its children (10, 11, 12,...), and so on, until we find the k
th number.
We can use a function to calculate the number of nodes between two numbers in the lexicographical tree.
curr = 1
(the starting number) and k = k - 1
(since we start from the first number).k
becomes 0.
curr
to curr + 1
using a helper function steps(n, curr, curr + 1)
.k >= steps
, it means the k
th number is not in the subtree rooted at curr
. So, decrement k
by steps
and move to the next sibling (curr++
).k
th number is in the subtree rooted at curr
. So, decrement k
by 1 (move to the first child) and move to the first child (curr *= 10
).curr
.steps(n, n1, n2)
:This function calculates how many numbers are between n1
and n2
in the lexicographical order, without exceeding n
.
steps = 0
.n1 <= n
:
min(n + 1, n2) - n1
to steps
.n1
and n2
by 10 to go to the next level in the lexicographical tree.steps
.def findKthNumber(n: int, k: int) -> int:
def steps(n: int, n1: int, n2: int) -> int:
steps = 0
while n1 <= n:
steps += min(n + 1, n2) - n1
n1 *= 10
n2 *= 10
return steps
curr = 1
k -= 1
while k > 0:
step = steps(n, curr, curr + 1)
if step <= k:
curr += 1
k -= step
else:
curr *= 10
k -= 1
return curr
n = 1
, k = 1
: Returns 1.n = 13
, k = 2
: Returns 10.