字典序的第K小数字

180 阅读1分钟

给定整数 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;
    }
}