持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第26天,点击查看活动详情
题目描述
给你一个整数 n ,请你在无限的整数序列 [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ...] 中找出并返回第 n 位上的数字。
示例 1:
输入:n = 3
输出:3
示例 2:
输入:n = 11
输出:0
解释:第 11 位数字在序列 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, ... 里是 0 ,它是 10 的一部分。
提示:
- 1 <= n <= 231 - 1
思路
首先要理解题意,看了示例2,大概可以看懂,就是每个数字位算1位,返回12345678910111213...这个无限序列的第n位。
理解了题意之后,我们整体思路是,先确定第n位是第x个整数,然后确定是这个整数中的第y位,然后求得这一位。要确定第n位是第x个整数,我们分成2步:
- 确定X是个len位数
- 确定是len位数的第k个自然数
那如何确定len呢?
我们尝试找一下规律:
- len=1,数字是从1~9,总共有9个
- len=2,数字是从10~99,总共有90个
- len=3,数字是从100~999,总共有900个
我们似乎找到了规律,按照上面的继续推理,4位数共有9000个,5位数共有90000个,可以不断向后推演。
其实上述的len位数的自然数个数,是可以通过代数的知识来解的,第1个len位数是10^(len-1),最后1个len位数是10^len-1,所以len位数总共就有10^len-1 - 10^(len-1) + 1 = 9*10^(len-1)个。获取了自然数个数,那len位数总共占用的位数就是len*(9*10^(len-1))。有了这个公式,我们就可以方便的计算出len位数的数字总共占用的位数,我们可以通过循环减的方式,确定len的值,同时,n的余数就是还剩下的偏移。因为len位数的数字,每个都占用len位,可以计算出偏移的k,分成2种情况:
- n % len == 0,处理起来最简单,
k = n / len,且刚好是这个自然数的最后1位,通过x % 10的方式就可以获取解; - n % len != 0,
k = n / len + 1,剩余的位数为n %= len,需要通过(int)(((num + 1) / (long)Math.pow(10, len-n)) % 10)来求解。
Java版本代码
class Solution {
public int findNthDigit(int n) {
int len = 1;
long lenCnt = 9;
while (n > lenCnt) {
n -= lenCnt;
len++;
lenCnt = 9 * len * (long)Math.pow(10, len - 1);
}
long num = (long)Math.pow(10, len - 1) + n / len - 1;
n %= len;
if (n == 0) {
return (int)(num % 10);
} else {
return (int)(((num + 1) / (long)Math.pow(10, len-n)) % 10);
}
}
}