思路:
锁定范围,算出具体数值,计算偏移,获得值。
1.锁定范围,我们要确定当前的 n 是在1位数,2位数,还是3位数。
2.计算出这个n具体所对应的值,例如10 对应10,11对应的10.
3.计算出偏移,10对应的是10的第一位数字,11对应的是10 的第二位数字,所以我们要算出他是具体的第几位数字
4.返回。
举个例子1001。
序列的前10位是0~9,这些都是1位数字,1001 > 10,所以它并不在这些数字里面,所以我们要跳过这一序列,再从后面紧跟的序列中找到第991(1001 - 10 = 991)位的数字。
接下来180位数字是90个数字组成,分别是10~99,由于991 > 180,所以它也不在两位数的范围内,所以跳过,继续寻找881位(991 - 180 = 881)
接下来是2700 位数字,由900个数字组成,分别是100 ~999的三位数,881 < 2700,所以它就是三位数字其中的某一位数字。
881 /3 = 270;
881 %3 = 1;
所以这就意味着,他是三位数字的第270个数字,也就是100+270;实际数字就是370;而偏移为 1, 也就是说它指向第1个数字,也就是7.
public int findNthDigit(int n) {
if(n < 0) return -1;
int digits = 1;
while(true){
long number = countOfInteger(digits);
if(n < digits* number){
return digitAtIndex(n,digits);
}
n -= digits*number;
digits++;
}
}
//获得m位的数字总共有多少个
private int countOfInteger(int digits){
//一位数字只有10个
if(digits == 1){
return 10;
}
//两位数字有90个,10-99
//三位数字都900个 100-999
int count = (int) Math.pow(10,digits-1);
return 9*count;
}
//已知数字的位数时获取结果
private int digitAtIndex(int index , int digits){
if(digits == 1) return index;
//获得具体的数值,从最初值 + 偏移值就等于 实际值
long number = beginNumber(digits) + index/digits;
//算出在具体的哪一位偏移,如果是0,是3位数字,那么就只能从后往前/10 ,/10 两次。
//如果是1,从后向前/10 一次,
long offset = digits - index % digits;
for(long i = 1;i < offset ;i++){
number/=10;
}
//最后要对最后一位进行获取,返回
return (int)number%10;
}
//获取m位数字的最小值,例如2位数字的最小值为10,三位数字最小值为100
private long beginNumber(int digits){
if(digits == 1)return 0;
return (int)Math.pow(10,digits-1);
}