记录两道与数字的字典序排数相关的题目(字节常考)
把数字的字典序画出来看看马上就明白了。
class Solution {
public List<Integer> lexicalOrder(int n) {
List<Integer> ans = new ArrayList<>();
int cur = 1;
for(int i = 0; i < n; i++) {
ans.add(cur);
if(cur * 10 <= n)
cur *= 10;
else {
// 枚举到当前前缀的最深处了,需要回到上一层并到下一个同层节点
while(cur % 10 == 9 || cur >= n)
cur /= 10;
cur++;
}
}
return ans;
}
}
说人话核心思想就是用getSteps()求以一个数为根结点的字数总共包括多少个节点stpes;如果steps<=k;则说明我们要找的数不在这个子树里,直接用k减去steps,然后往右边走,cur++即可;
若steps>k,则说明我们要找到数在这个子树里,则cur * =10,k --;进入下一层搜索;
重复上述搜索直到k为0 为止。
可能你会想可以和上面那道一样一个个从小到大去遍历字典序直至第k个,但看一下k的取值范围就会发现很容易超时,所以只能通过求steps加快搜索;
class Solution {
public int findKthNumber(int n, int k) {
int cur=1;
k--;
while(k>0){
int step=getSteps(cur,n);
if(step<=k){
k-=step;
cur++;
}
else{
cur*=10;
k--;
}
}
return cur;
}
//注意要下面的long型,否则会越界
public int getSteps(int cur,long n){
int step=0;
long first=cur,last=cur;
while(first<=n){
step+=last-first+1;
first=first*10;
last= Math.min(last*10+9,n);
}
return step;
}
}