解法
不会做,参考了这篇博文
实际上代码很简短,只能理解一下了
按上文参考文章说的,假设n为无穷大时,每个数字都可以表示成一个十叉树森林里的一个节点:
比如,第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+1−10i−1个,所以
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(i−1)+n+1−10i−1
综上所述得到递推关系: 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(i−1)+max(n+1,10i−1(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=x∗10,此外k要减1,表示x已经算过了
- 如果 C o u n t ( l ) < k Count(l)<k Count(l)<k,表示要找的第k个元素肯定不在这个子树里,那么我们移动到下一个父结点,也就是这个父结点的下一个兄弟: x + 1 x+1 x+1,这时k要减去 C o u n t ( l ) < = k − 1 Count(l)<=k-1 Count(l)<=k−1,表示我们走过了这么多节点
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