2021.05.13字典序第k小数字
(题目来源:https://leetcode-cn.com/problems/k-th-smallest-in-lexicographical-order/)
题目描述
给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。
数据规模和约定
1 ≤ k ≤ n ≤ 10^9。
思路
搜索第k小数字时可以构造一个“十叉搜索前缀树”,如下图:

我们可以发现 ①这个十叉搜索树是一个完全十叉树,但不是一个满十叉树,其最后一个节点即为n。②前序遍历1,10,101,102…即为其按照字典序升序排列的顺序。
为求解该问题,我们需要解决三个子问题:
子问题1:如何找到一个前缀下所有子节点的个数?
可以发现,如果是满二叉树,那么同一层前缀下的子节点个数是相等的:

所以可以采取如下策略,即cur从10开始遍历,next从11开始遍历,如果没有到达底部(即cur < n),那么往下一层遍历,即cur*=10, next *= 10,10前缀下的子节点个数为110-100 = 10; //cur为遍历过程中指定prefix下的cur根节点。
子问题2和3:如果第k个数在当前前缀下,那么我们该如何遍历到它?如果第k个数不在当前前缀下,我们又该如何继续遍历?
如果第k个数在当前前缀的子树中,那么往下一层进行遍历,否则进入当前层的下一前缀树进行搜索。依次迭代。
代码
public int findKthNumber(int n, int k) {
int cur = 1;
int prefix = 1;
while(cur < k) {
int tmp = count(n,prefix);
if(tmp + cur > k) { //res在此节点下
prefix *= 10;
cur++;
} else { //res不在此节点下
cur += tmp;
prefix++;
}
}
return prefix;
}
//返回当前前缀为根的子节点个数
int count(int n, int prefix) {
long cur = prefix;
long next = cur+1;
int cnt = 0;
while(cur <= n) {
cnt += Math.min(n+1, next)-cur;
next *= 10;
cur *= 10;
}
return cnt;
}
本文介绍了一种高效算法,用于寻找1到n范围内字典序第k小的数字。通过构建十叉搜索前缀树并采用递归策略,解决了如何计算特定前缀下的子节点数量问题,进而迭代确定目标数字。
9925

被折叠的 条评论
为什么被折叠?



