386:字典序排数 (中等)
给定一个整数 n, 返回从 1 到 n 的字典顺序。
例如,
给定 n =1 3,返回 [1,10,11,12,13,2,3,4,5,6,7,8,9] 。
请尽可能的优化算法的时间复杂度和空间复杂度。 输入的数据 n 小于等于 5,000,000。
来源:力扣(LeetCode)
思路:
刚开始看到这个题目,主要是不太清楚什么是字典序
看下图:每一个节点都拥有 10 个孩子节点,因为作为一个前缀 ,它后面可以接 0~9 这十个数字。整个字典序排列也就是对十叉树进行先序遍历。1, 10, 100, 101, … 11, 110 …
字典序 简而言之,就是根据数字的前缀进行排序,
比如 10 < 9,因为 10 的前缀是 1,比 9 小。
再比如 112 < 12,因为 112 的前缀 11 小于 12
假设n=111
1,10,100,每次都乘以 10
100,101,102,…,109,每次加 1
109,19,99,末尾为 9 则先除以 10 直到末尾不为 9 再加 1
111,排到 n 了则先除以 10 再加 1
代码实现
public List<Integer> lexicalOrder(int n) {
List<Integer> list = new ArrayList<>();
int num = 1;
list.add(1);
for(int i = 1;i<n;i++) {
if(num*10 <=n) {
num*=10;
list.add(num);
}
else {
while(num%10 ==9 || num ==n) {
num/=10;
}
num++;
list.add(num);
}
}
return list;
}
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。
来源:力扣(LeetCode)
思路
由于做了386题,再来做这题,就会上来暴露求解,代码如下,时间会超时。因为那样,你是要把没个数给求出来。而这里,我们只需要把子节点得个数确定好,就可以了。
public int findKthNumber(int n, int k) {
if(k==1) return 1;
List<Integer> list = new ArrayList<>();
int num = 1;
int count =1;
list.add(1);
for(int i = 1;i<n;i++) {
if(num*10 <=n) {
num*=10;
list.add(num);
count++;
}
else {
while(num%10 ==9 || num ==n) {
num/=10;
}
num++;
list.add(num);
count++;
}
if(count == k)
break;
}
return list.get(k-1);
}
按给出得实例,作为分析例子:
[1, 10, 11, 12, 13, 2, 3, 4, 5, 6, 7, 8, 9]
标注部分为同一层两个相邻的节点的子节点的个数。
1:当前节点为 cur(从cur = 1 开始),则同一层的下一个节点为 curr+1;
2:计算节点 curr到节点curr+1之间的子节点个数step
3:如果子节点个数 大于 k,说明第k小的树一定在子节点中,那么继续向下一层寻找:cur *=10; k -= 1;
(原因:向下一层寻找,肯定要减少前面的父节点,即 在上一层中的第k个数,在下一层中是第k-1个数)
4:如果子节点个数 小于或者等于 k,说明第k小的树不在子节点中,继续向同一层下一个节点寻找:curr +=1; k -= steps;
(原因:向下一层寻找,肯定要减少前面的所有的字节点)
以此类推,直到k为0推出循环,此时cur即为所求。
代码实现
public int findKthNumber(int n, int k) {
int cur =1;
k =k-1;
while(k>0){
long step =0;
long first = cur;
long last = cur+1;
while(first<=n){
step+=Math.min((long)n+1,last)-first;
first*=10;
last*=10;
}
if(step<=k){
cur+=1;
k-=step;
}
else{
cur*=10;
k=k-1;
}
}
return cur;
}
注意:定义得step,first,last 定义为Long,不然会溢出,导致错误