找规律:
0 占第0位
1~9 共9x1 = 9个数字 占位9x1 = 9 位
10~99 共9x10 = 90个数字 占位90x2 = 180 位
100~999 共9x100 = 900个数字 占位900x3 = 2700 位
…
规律是不是很好理解啦,算法的逻辑就是:我们依次算一下占位数字,并不断地累加得到当前的总占位数,并判断和输入n的关系,总占位数小于n的话说明,第n位不在目前的范围內,继续累加;否则,说明在范围,然后找到相应数字返回。
举个例子秒懂:
假设输入n为14,我们想找到第14位:
(1)此时设置当前位置为0的位置 temp=0
(2)占1位的数字有9个: num=9,(1~9,除了0因为temp已设为0了)
(3)占1位 base=1
(4)我们判断一下,当占1位的数字都走完了,目前一共占到了多少位: temp + num x base = 0 + 9x1 = 9,说明占1位的数字走完后,当前占到了第9位。(更新temp=temp + num x base = 9)
(5)和输入的值比较下,9 < 14,说明我们想找的第14位不在当前占1位的数字中。
(6)那就有可能在占2位的数字中,所以这一轮我们看看占2位的数字(10~99):
每个数字占位 base = base + 1 = 2
有多少个数字 num = num x 10 = 90
再回到第(4)步,算一下当占2位的数字也都走完了,目前一共占到了多少位
temp + num x base = 9 + 90 x 2 = 189
说明当占2位的数字走完后,当前占到了第189位
再回到第5步,发现 189 > 14,说明我们想找到的数字就在10~99之间
此时,循环终止…因为没必要再往下算占3位的情况了
(7)我们知道第14位就在10~99之间的话就很好办了:
前一轮我们知道占1位的数字走完后,占到了第9位,那我们想找的第14位的值也就是9之后的第5位:
14 - 9 = 5位
占两位的数字中(10~99),第一个起始数字是10,(10 = 10的1次方,也就10的(base-1)次方)
由于10~99这个范围内的数字,都是占base=2位,
所以 5/2 = 2
10 + 2 = 12,第14位就在数字12里
5%2 = 1,说明第14位就是数字12中的第一个位置值,如果把12当成字符串,那就是下标为0的值
“12”.charAt(1-1) = 1
最终我们找到了这个1
验证下0123456789101112…第14位确实是1
联系上面的思路,带到下面的代码,很好理解啦。
注意大数越界问题,所以这里用long型
class Solution {
public int findNthDigit(int n) {
if(n<0) return 0;
else if(n>=0 && n<=9) return n;
else {
long m = n;
long temp = 0;
long base = 1;
long num = 9;
char res = '0';
while((temp+base*num) < m) {
temp += base*num;
base += 1;
num *= 10;
}
long a = (m-temp)/base;
long b = (m-temp)%base;
if(b!=0) {
long c = (long) (Math.pow(10, base-1) + a);
res = String.valueOf(c).charAt((int)b-1);
}else {
long c = (long) (Math.pow(10, base-1) + a - 1);
res = String.valueOf(c).charAt((int)base-1);
}
return Integer.parseInt(String.valueOf(res));
}
}
}