LeetCode440. 字典序的第K小数字

1、题目描述

https://leetcode-cn.com/problems/k-th-smallest-in-lexicographical-order/

给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。注意:1 ≤ k ≤ n ≤ 10^9。

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

2、代码详解

求字典序第k个就是上图前序遍历访问的第k节点!但是不需要用前序遍历,如果我们能通过数学方法求出节点1和节点2之间需要走几步,减少很多没必要的移动。

只需要按层节点个数计算即可,

  • 图中节点1和节点2在第二层,因为n = 13,节点1可以移动到节点2(同一层)
  • 所以在第二层需要移动1步。(min(13 + 1, 2) - 1)= 1,即在该层移动需要一步从节点1到节点2
  • 第三层,移动个数就是 (13 - 10 + 1) = 4 ,(min(13 + 1, 20) - 10)

所以节点1到节点2需要移动 1 + 4 = 5 步

  • 当移动步数小于等于k,说明需要向右节点移动,图中就是节点1移动到节点2。
  • 当移动步数大于k,说明目标值在节点1和节点2之间,我们要向下移动!即从节点1移动到节点10。

LeetCode440. 字典序的第K小数字_第1张图片

LeetCode440. 字典序的第K小数字_第2张图片

https://leetcode-cn.com/problems/k-th-smallest-in-lexicographical-order/solution/shi-cha-shu-by-powcai/

class Solution:
    def findKthNumber(self, n, k):
        # 计算移动步数
        def cal_steps(n, first, last):
            step = 0
            while first <= n:  # 比如n=13
                step += min(n + 1, last) - first
                # min(13 + 1, 2) - 1 = 1
                # min(13 + 1, 20) - 10 = 4
                first *= 10
                last *= 10
            return step  # 从节点1到节点2需要移动 1 + 4 = 5 步

        cur = 1  # cur设置为1,因为k从1开始
        k -= 1  # 扣除掉第一个0节点

        while k > 0:
            steps = cal_steps(n, cur, cur + 1)
            # 当移动步数小于等于k,说明需要向右节点移动,图中就是节点1移动到节点2
            # 第k个数不在以cur为根节点的树上
            if steps <= k:
                k -= steps
                cur += 1  # cur在字典序数组中从左往右移动
            # 当移动步数大于k,说明目标值在节点1和节点2之间,要向下移动!即从节点1移动到节点10
            else:  # 在子树中
                k -= 1  # 刨除根节点
                cur *= 10  # cur在字典序数组中从上往下移动

        return cur

https://leetcode-cn.com/problems/k-th-smallest-in-lexicographical-order/solution/yi-tu-sheng-qian-yan-by-pianpianboy/

你可能感兴趣的:(Array)