440. K-th Smallest in Lexicographical Order

解法

不会做,参考了这篇博文
实际上代码很简短,只能理解一下了
按上文参考文章说的,假设n为无穷大时,每个数字都可以表示成一个十叉树森林里的一个节点:
1

比如,第0层根结点1下一层管着10-19,下二层管着100-199;第1层根结点10下管着100-109……以此类推。
数字按字典序排列就是这个森林按先根遍历得到的序列。

我们发现父结点x管着的下一层的所有子结点为: C h i l d r e n ( x ) = [ 10 x , 10 ( x + 1 ) ) Children(x) = [10x, 10(x+1)) Children(x)=[10x,10(x+1)),但是如果某些节点超过了n,就要被剪掉,所以有:
C h i l d r e n ( x ) = [ 10 x , max ⁡ ( 10 ( x + 1 ) , n + 1 ) ) Children(x) = [10x, \max(10(x+1), n+1)) Children(x)=[10x,max(10(x+1),n+1))
我们怎么知道父节点 x x x以下所有子结点的个数呢?显然,随着层数的增加节点的值也在增加,总会加到一层,这层节点不完全的。
比如说当父结点为x时,它的子树截止到i层时的总节点数为 C o u n t ( i ) Count(i) Count(i)

  • 假如只有0层,子结点只有1个, C o u n t ( 0 ) = 1 Count(0)=1 Count(0)=1
  • 假如有1层,子结点有1+(20-10)=11个, C o u n t ( 1 ) = 11 Count(1)=11 Count(1)=11
  • 假如有2层,子结点有1+(20-10)+(200-100)=111个, C o u n t ( 2 ) = 111 Count(2)=111 Count(2)=111
  • 假如在第i层中断了,这层子结点将有 n + 1 − 1 0 i − 1 n+1-10^{i-1} n+110i1个,所以 C o u n t ( i ) = C o u n t ( i − 1 ) + n + 1 − 1 0 i − 1 Count(i)=Count(i-1)+n+1-10^{i-1} Count(i)=Count(i1)+n+110i1
    综上所述得到递推关系: C o u n t ( i ) = C o u n t ( i − 1 ) + max ⁡ ( n + 1 , 1 0 i − 1 ( x + 1 ) ) Count(i)=Count(i-1)+\max(n+1,10^{i-1}(x+1)) Count(i)=Count(i1)+max(n+1,10i1(x+1))

假如以x为父节点的子树最大有l层,那么这个子树将有 C o u n t ( l ) Count(l) Count(l)个节点:

  • 如果 C o u n t ( l ) > = k Count(l)>=k Count(l)>=k,要找的第k个元素肯定在这个子树里,那么深入下一层找,先找以第一个子节点为根的子树: x = x ∗ 10 x = x*10 x=x10,此外k要减1,表示x已经算过了
  • 如果 C o u n t ( l ) &lt; k Count(l)&lt;k Count(l)<k,表示要找的第k个元素肯定不在这个子树里,那么我们移动到下一个父结点,也就是这个父结点的下一个兄弟: x + 1 x+1 x+1,这时k要减去 C o u n t ( l ) &lt; = k − 1 Count(l)&lt;=k-1 Count(l)<=k1,表示我们走过了这么多节点
class Solution(object):
    def findKthNumber(self, n, k):
        """
        :type n: int
        :type k: int
        :rtype: int
        """

        cur = 1
        k -= 1
        while k:
            i = cur
            j = cur+1
            count = 0
            while i<=n:
                count += min(n+1,j)-i
                i*=10
                j*=10
            if count<=k:
                k -= count
                cur += 1
            else:
                k -= 1
                cur = cur*10
        return cur
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值