给定整数 n
和 k
,返回 [1, n]
中字典序第 k
小的数字。
输入: n = 13, k = 2
输出: 10
解释: 字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的数字是 10。
10叉树:
class Solution {
public int findKthNumber(int n, int k) {
// 遍历到字典序中第p个位置的数
int p = 1;
// 起始前缀从1开始
int prefix = 1;
// 如果还没有遍历到第k个数继续查找
while(p < k){
// 获取当前前缀的子节点个数
int cnt = getCnt(n,prefix);
// 如果包含当前前缀的节点个数 > k 则说明我们要找的 第k小的数就在这个前缀子树当中
if (p + cnt > k){
// 此时我们就要向下查找
prefix *= 10;
// 指针指向前缀子树的第一个子节点
p++;
}else if (p + cnt <= k){ // 反之我们扩大前缀 进入问题3
prefix++;
// 指针指向扩大前缀的第一个子节点位置
p+=cnt;
}
}
return prefix;
}
// 获取我们当前前缀下的子节点个数
int getCnt(int n , int prefix){
// 设置当前前缀
long curPrefix = prefix;
// 设置下一前缀
long nextPrefix = prefix + 1;
// 用于计数
int cnt = 0 ;
while (curPrefix <= n){
// 下一个前缀的起点减去当前前缀的起点的值 这里需要注意 如果next 大于上界n时那么可能出现左前缀不满的情况,为了避免这种情况的发生 取上界点值 进行当前前缀的值 就是子节点数,为何n+1 因为你要包括前缀树根节点
cnt += Math.min(n+1,nextPrefix) - curPrefix;
curPrefix *= 10;
nextPrefix *= 10;
}
return cnt;
}
}