1、题目描述
https://leetcode-cn.com/problems/k-th-smallest-in-lexicographical-order/
给定整数 n
和 k
,找到 1
到 n
中字典序第 k
小的数字。注意:1 ≤ k ≤ n ≤ 10^9。
输入:
n: 13 k: 2
输出:
10
解释:
字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的数字是 10。
2、代码详解
求字典序第k个就是上图前序遍历访问的第k节点!但是不需要用前序遍历,如果我们能通过数学方法求出节点1和节点2之间需要走几步,减少很多没必要的移动。
只需要按层节点个数计算即可,
- 图中节点1和节点2在第二层,因为n = 13,节点1可以移动到节点2(同一层)
- 所以在第二层需要移动1步。(min(13 + 1, 2) - 1)= 1,即在该层移动需要一步从节点1到节点2
- 第三层,移动个数就是 (13 - 10 + 1) = 4 ,(min(13 + 1, 20) - 10)
所以节点1到节点2需要移动 1 + 4 = 5 步
- 当移动步数小于等于k,说明需要向右节点移动,图中就是节点1移动到节点2。
- 当移动步数大于k,说明目标值在节点1和节点2之间,我们要向下移动!即从节点1移动到节点10。
class Solution:
def findKthNumber(self, n, k):
# 计算移动步数
def cal_steps(n, first, last):
step = 0
while first <= n: # 比如n=13
step += min(n + 1, last) - first
# min(13 + 1, 2) - 1 = 1
# min(13 + 1, 20) - 10 = 4
first *= 10
last *= 10
return step # 从节点1到节点2需要移动 1 + 4 = 5 步
cur = 1 # cur设置为1,因为k从1开始
k -= 1 # 扣除掉第一个0节点
while k > 0:
steps = cal_steps(n, cur, cur + 1)
# 当移动步数小于等于k,说明需要向右节点移动,图中就是节点1移动到节点2
# 第k个数不在以cur为根节点的树上
if steps <= k:
k -= steps
cur += 1 # cur在字典序数组中从左往右移动
# 当移动步数大于k,说明目标值在节点1和节点2之间,要向下移动!即从节点1移动到节点10
else: # 在子树中
k -= 1 # 刨除根节点
cur *= 10 # cur在字典序数组中从上往下移动
return cur