题目链接:
力扣https://leetcode-cn.com/problems/k-th-smallest-in-lexicographical-order/
【分析】首先我们假设有一个get(pre, n)这样一个函数,可以找出[1, n]中所有以pre开头的数字的个数。那么对于第k个,如果当前查出来的个数num<k,说明第k个元素肯定不以当前这个pre开头,那么我们把pre+1,同时把k-num,意思为跳过前k个,因为这个k个以pre开头的元素肯定在以pre+1的元素前面。如果当前查出来的个数num>k,说明第k个肯定在这个里面,那么我们需要再细细划分这个以pre开头的子集,方法为将pre*10,从字典树的角度上来看就是继续找下一层的元素,同时需要将k-1,意思为跳过pre这个元素。直到k==1,这时的pre就是要找的元素了。
接下来看看get函数怎么实现,我们以12456和123为例来看,首先至少pre要包括3位的123,加下来四位的123x,记下来五位的123xx:
3位的:只有123这1个。 1
4位的:1230-1239一共10个。 10
5位的:12300-12399一共100个。 100
于是我们可以让t=1,pre每*10,t也*10,累加起来。
但是这样会有一定的问题就是,5位的能到12399,但是如果只有12333呢。所以最后pre和n位数相同的时候我们需要做一个判断,如果此时pre完全>n,那么一个也没有,如果pre<n,要看n和pre的差值,如果>t,最多也只有t个元素,如果<t,就是二者的差值+1。
class Solution {
public long get(int pre, int n){
int t = 1;
long ans = 0;
double m = (double)n / 10;
while(pre <= m){
ans += t;
t *= 10;
pre *= 10;
}
int rem = n - pre;
if(rem >= t) ans += t;
else if(rem < 0);
else ans += rem + 1;
return ans;
}
public int findKthNumber(int n, int k) {
int pre = 1;
while(k > 1){
long num = get(pre, n);
// System.out.print(pre);
// System.out.print(" ");
// System.out.print(num);
// System.out.print(" ");
// System.out.println(k);
if(num >= k) {
pre *= 10;
k -= 1;
}
else {
pre += 1;
k -= num;
}
}
return pre;
}
}