描述
数字以 0123456789101112131415… 的格式作为一个字符序列,在这个序列中第 2 位(从下标 0 开始计算)是 2 ,第 10 位是 1 ,第 13 位是 1 ,以此类题,请你输出第 n 位对应的数字。
数据范围: 0 ≤ n ≤109
示例1
输入: 0
返回值:0
示例2
输入: 2
返回值:2
示例3
输入: 10
返回值:1
示例4
输入: 13
返回值:1
分析:
按数的位数分类考虑:
-
1位数, 数的范围是1~9, 共有 9-1+1 = 9 = 9·1 = 9⋅100 个;
-
2位数, 数的范围是10~99, 共有 99-10+1 = 90 = 9·10 个 = 9⋅101个;
-
3位数, 数的范围是100~999, 共有 999-100+1 = 900 = 9·100 个 = 9⋅102个;
以此类推
…
k位数, 共有 9⋅10 k−1 个。
怎么找第n个数字位?
接下来, 我们要找第n个digit(第n个位置, 从1开始算, 不从0开始算), 可以这样做:
每次从k中减去9⋅10 k−1 ⋅k, 能减将则尽量多地减, 然后记录剩下的余数。
n − 9⋅1⋅1(末尾乘上的1表示长度为1的数) − 9⋅10⋅2(长度为2的数)−9⋅102 ⋅3(长度为3的数)−…
下面的代码中我们用while实现, while循环结束时 n 被更新为剩下的余数。
为什么代码中用的是 curNum = (n - 1)/len, 而不是 n/len?
可以举1个简单的例子来验证。
比如, 如果 n = 15, 结果应该是多少? 其实可以用leetcode的test case试一下可以看到expected的答案是2。
while循环结束时候, n = 15-9 = 6, 而此时 len=2, 即此时统计的数是二位数。
如果使用 curNum = (n - 1)/len
, 那么: curNum = (6-1)/2 + 10 = 12, 且接下来可以得到第15个digit就是2, 符合题意。
而如果使用 curNum = n/len
, 那么: curNum = 6/2 + 10 = 13, 且接下来可以得到第15个digit就是1, 不合题意。
代码:
class Solution {
public:
int findNthDigit(int n) {
int len = 1, weigh = 1; /* len表示当前数(十进制)的位数, weigh表示当前位的权重(10^i)... */
while (n > (long long) 9 * weigh * len) /* 转换成long long, 防止整型溢出 */
{
n -= 9 * weigh * len;
len++;
weigh *= 10;
}
int curNum = (n - 1)/len + weigh; // curNum是含有所找digit的那个数, 整个数列的第一个数是1
int resDigit = 0;
for (int i = (n-1) % len; i < len; i++) // 从低位向高位移动扫描, 根据离末位的偏移量找到所找的数字
{
resDigit = curNum % 10;
curNum /= 10;
}
return resDigit;
}
};
运行时间:4ms
超过27.76% 用C++提交的代码
占用内存:544KB
超过1.48%用C++提交的代码
参考于yanglr