十叉树之字典序的第K小数字

LeetCode 440. 字典序的第K小数字

给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。

输入:
n: 13   k: 2

输出:
10

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

先来个暴力超时解法

class Solution:
    def findKthNumber(self, n: int, k: int) -> int:
        s = []
        for i in range(1, n + 1):
            s.append(str(i))
        s.sort()
        return int(s[k - 1])

妥妥的超时
再看题解,十叉树。活久见,接着往下看
十叉树,用题目的测试用例来举例子。
在这里插入图片描述
我们求字典序第k个就是上图前序遍历访问的第k节点!但是不需要用前序遍历,如果我们能通过数学方法求出节点1和节点2之间需要走几步,减少很多没必要的移动。

其实只需要按层节点个数计算即可,图中节点1和节点2在第二层,因为n = 13,节点1可以移动到节点2(同一层)所以在第二层需要移动1步

第三层,移动个数就是 (13 - 10 + 1) = 4 (min(13 + 1, 20) - 10)

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

移动步数小于等于k,说明需要向右节点移动,图中就是节点1移动到节点2

移动步数大于k,说明目标值在节点1和节点2之间,我们要向下移动!即从节点1移动到节点10

class Solution:
    def findKthNumber(self, n: int, k: int) -> int:
        cur = 1
        k -= 1
        while k > 0:
            steps = self.cal_step(n, cur, cur + 1)
            if steps <= k: # 需要向右节点移动
                k -= steps # 先把下一层走完,再往右走
                cur += 1 # 往右
            else: # 目标值在节点1和节点2之间,要向下移动
                k -= 1 # 走一步
                cur *= 10 # 往下,1走到10
        return cur

    # 计算从n1到n2要走的步数
    # 例:第一轮计算从1到2的步数,然后判断走的步数和k的大小,判断是在1和2之间还是2之后
    def cal_step(self, n, n1, n2):
        step = 0
        while n1 <= n:
            step += min(n2, n + 1) - n1
            n1 *= 10
            n2 *= 10
        return step
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值