440. 字典序的第K小数字

 

难度困难

给定整数 n 和 k,返回  [1, n] 中字典序第 k 小的数字。

 

示例 1:

输入: n = 13, k = 2
输出: 10
解释: 字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的数字是 10。

示例 2:

输入: n = 1, k = 1
输出: 1

 

提示:

  • 1 <= k <= n <= 109

 

 

 

class Solution:
    def findKthNumber(self, n: int, k: int) -> int:
        def get_cnt(prefix,n):
            prefix_next = prefix+1
            cnt = 0
            while prefix <= n:
                cnt += min(n+1,prefix_next) - prefix
                prefix *= 10
                prefix_next  *= 10
            return cnt
            
        prefix = 1
        cnt = 1
        while cnt < k:
            cur_cnt = get_cnt(prefix,n)
            if cnt+cur_cnt > k: # 在当前前缀下,进入下一层
                prefix*=10 
                cnt +=1
            else:
                prefix+=1 #当前层左移动
                cnt += cur_cnt
        return prefix

 

class Solution {
    // 根据 前缀 和 限制 n 查找该前缀下有多少可能值
    int getCnt(int x, int limit) {
        int ans = 0;
        string a = to_string(x), b = to_string(limit);
        int n = a.length(), m = b.length(), k = m - n;
        int u = stoi(b.substr(0, n));
        for (int i = 0; i < k; ++i) ans += pow(10, i);
        if (x < u) ans += pow(10, k);//3,239///1+10
        else if (x == u) ans += limit - x * pow(10, k) + 1;//23,239///1+(239-230+1)
        else if (x > u) ans += 0;//30,239///1 + 0;
        return ans;
    }
public:
    int findKthNumber(int n, int k) {
        int cnt = 1;
        int prefix = 1;
        while(cnt < k) {
            int count = getCnt(prefix, n);
            if (cnt + count > k) {
                /// 说明第k个数,在这个前缀范围里面,去子树寻找
                prefix *= 10;
                cnt++;
            } else if (cnt+count <= k) {
                /// 说明第k个数,不在这个前缀范围里面,前缀需要扩大+1
                prefix++;
                cnt += count;
            }
        }
        return prefix;
    }
};

 

posted @ 2022-06-07 00:01  乐乐章  阅读(66)  评论(0编辑  收藏  举报