[leetCode]剑指 Offer 44. 数字序列中某一位的数字
解法
直观解法是逐一枚举每个数字计算每个数字的数位和直到大于输入n,然后再从该数字中找出对应的那一位。
更快的解法是我们可以把数字序列0,1,2,3...
看成由不同位数数字组成的几部分序列0~9, 10 ~ 99,100 ~ 999.....
输入n所在的数字存在于某个子序列中。可以通过计算每个序列所含位数来跳过这个序列。以n为1001为例
0~9 一共10位小于1001,所以n一定在之后的序列中,可以跳过该序列 n - 10 = 991,10 ~99 有90个数字180位, 991 > 180 所以可以跳过,n = 991 - 180 = 881, 100 ~ 999 有900个数字 2700位, 881 < 2700,所以n位于3位数组成的序列中,此时881 = 270 * 3 +1,所以n位于从100开始后的270个数的第一位即370中的7。
代码如下:
class Solution {
public int findNthDigit(int n) {
if(n < 0) return -1;
// 位数
long digits = 1;
while(true) {
// 当前位数一共有多少位数字
long numbers = countOfIntegers(digits);
// digits * numbers 为数位数,会超过int最大值所以要用long
if(n < numbers * digits)
return findNthDigit(n,digits);
n -= digits * numbers;
digits++;
}
}
// 计算m位数字一共有多少个
private long countOfIntegers(long digits) {
if(digits == 1)
return 10L;
long result = (long)Math.pow(10,digits -1);
return (long)(result * 9);
}
private int findNthDigit(int n,long digits) {
// number为n为数所在的数字
long number = beginNumber(digits) + n / digits;
long indexFromRight =digits - n % digits;
for(int i = 1; i < indexFromRight; ++i)
number /= 10;
return (int)(number % 10);
}
private long beginNumber(long digits){
if(digits == 1)
return 0;
return (long)Math.pow(10,digits-1);
}
}