1.题目描述
给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。
注意:1 ≤ k ≤ n ≤ 109。
示例 :
输入:
n: 13 k: 2输出:
10解释:
字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的数字是 10。
2.解题思路
字典序排数可以看做是第一层节点分别为 1-9 的十叉树,然后我们在树上找到第 K 小的数字即可。因此,我们需要分别统计以 1-9 为根节点的每个树的节点个数。如果 K 小于当前树的节点个数,那么第 K 小的数字即在当前树中 (K - 1) ,我们进入子树继续查找;如果 K 大于当前树的节点个数,那么我们需要查找后面树中第 (K - 当前树节点) 小的数字。
其中,比较关键的步骤就是统计树中的节点个数:
首先我们初始化 cur = 1
然后我们让 left = cur,right = cur + 1,此时 right-left 就是第一棵树第一层的节点个数
接下来 left *= 10, right *= 10,这样就进入到了第二层,此时 right-left 就是第二层的节点个数,以此类推直到 left > n
但如果我们是统计 109 以内的字典序,进入第三层时,right 不能指向 200 而只能指向 109,此时 n-left+1 才是当前层的节点个数
假设我们统计完第一棵树的节点数为 node_num,
如果 K >= node_num,我们需要继续向后查找,在后面的树中查找第 K-node_num 小的数字,也即更新 cur += 1
如果 K < node_num,说明第 K 小的数字在子树中,我们需要进入子树继续向下查找,也即更新 cur *= 10
最后当 K=0 时,cur 指向的值即为所求。
3.代码实现
class Solution(object):
def findKthNumber(self, n, k):
"""
:type n: int
:type k: int
:rtype: int
"""
cur=1
k-=1
while k>0:
left,right=cur,cur+1
step=0
while left<=n:
step+=min(right,n+1)-left
left*=10
right*=10
# 向后查找
if step<=k:
k-=step
cur+=1
# 进入子树查找
else:
k-=1
cur*=10
return cur