440. 字典序的第K小数字
给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。
注意:1 ≤ k ≤ n ≤ 109。
示例 :
输入:
n: 13 k: 2
输出:
10
解释:
字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第二小的数字是 10。
解题思路
N个数字可以组织成为具有n个节点的10叉树,该树的前序遍历就是数字的字典序,如图所示
我们的目标就是需要找前序遍历的第k个节点
我们可以选择性的选择父节点遍历,不需要遍历前k个节点。
例如
输入:
n: 13 k: 6输出:
2解释:
字典序的排列是 [1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9],所以第六小的数字是 2。
我们可以通过计算出,以1开头有多少个节点,对比和k的关系。
- 以1为根节点的子树节点数量为5,如果k为6,说明不需要遍历以1为根节点的树,直接向左移动到以2为根节点的树上,继续遍历
- 以1为根节点的子树节点数量为5,如果k为2,说明我们需要遍历的节点必然在根节点1的子树上面,我们移动到根节点的最左子节点,继续遍历
如何计算子树的节点树
从上图可以观察出,每一层节点的数字都是单调递增的,例如10,11…19,20,因此我们通过计算根节点的最左节点来固定每一层的节点数
每一层我们需要计算的节点数,位于上图红线划分的区间中。
代码
class Solution {public int findKthNumber(int n, int k) {long cur=1;k--;while (k>0){int number = findingKthNumber(n, cur);if (k>=number){k-=number;cur++;}else {k--;cur*=10;}}return (int)cur;}//sum 上一层的数字public int findingKthNumber(int n, long cur) {long next=cur+1;long res=0;while (cur<=n){res+= Math.min(n-cur+1,next-cur);cur*=10;next*=10;}return (int)res;}
}