LeetCode 386——字典序的第 K 小数字

1. 题目

2. 解答

字典序排数可以看做是第一层节点分别为 1-9 的十叉树,然后我们在树上找到第 K 小的数字即可。因此,我们需要分别统计以 1-9 为根节点的每个树的节点个数。如果 K 小于当前树的节点个数,那么第 K 小的数字即在当前树中,我们进入子树继续查找;如果 K 大于当前树的节点个数,那么我们需要查找后面树中第 (K - 当前树节点) 小的数字。

其中,比较关键的步骤就是统计树中的节点个数,我们按照逐层统计的方法来进行,详见下图。

  • 首先我们初始化 cur = 1
  • 然后我们让 left = cur,right = cur + 1,此时 right-left 就是第一棵树第一层的节点个数
  • 接下来 left *= 10, right *= 10,这样就进入到了第二层,此时 right-left 就是第二层的节点个数,以此类推直到 left > n
  • 但如果我们是统计 109 以内的字典序,进入第三层时,right 不能指向 200 而只能指向 109,此时 right-left+1 才是当前层的节点个数

假设我们统计完第一棵树的节点数为 node_num

  • 如果 K >= node_num,我们需要继续向后查找,在后面的树中查找第 K-node_num 小的数字,也即更新 cur += 1
  • 如果 K < node_num,说明第 K 小的数字在子树中,我们需要进入子树继续向下查找,也即更新 cur *= 10

最后当 K=0 时,cur 指向的值即为所求。

class Solution {
public:
    int findKthNumber(int n, int k) {
        
        int cur = 1;
        k--;
        
        while (k > 0)
        {
            long long left = cur;
            long long right = cur + 1;
            int node_num = 0;
            
            while (left <= n) // 统计树中每一层的节点个数
            {
                node_num += min(right, (long long)(n+1)) - left;
                left *= 10;
                right *= 10;
            }
            
            if (node_num <= k) // 向后查找
            {
                k -= node_num;
                cur++;
            }
            else // 进入子树查找
            {
                k--;
                cur *= 10;
            }
        }
        
        return cur;       
    }
};

获取更多精彩,请关注「seniusen」!

posted @ 2019-03-27 15:23  seniusen  阅读(263)  评论(0编辑  收藏  举报