400.给你一个整数 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 的一部分。
- 最开始 n 对应的就是 n,但是当数字成为两位数之后就开始对不上了,所以能想到这题的关键在于随着数字位数的变化,如何找到 n 对应的结果,为了方便称呼先定义几个概念:
- 位数(digit):这个数字有几位,比如两位数,三位数
- 数位:比如数字 10,11,12 组成的序列 101112,其中每一位都是一个数位,其实也就是题目所说的序列上的某一位
- 数字(num),比如 10,11,12 ,这三个数都是数字
- 起始数字(start):某位数最小的数字,比如两位数的范围是 10~99,start 就是 10
- 数位数量(count):只算 n 位数包含的数位数量,比如两位数为 10~99 ,有 90 个 两位数(每个数的数位数量为 2),所以位数数量为 90 * 2 = 180
- 现在我们知道关键在于位数变化,所以研究位数变化带来的一些规律
- 位数递推公式:观察从一位数,两位数,三位数的变化,所以 digit(i+1) = digit(i) + 1
- 起始数字递推公式:最小一位数为 1,最小两位数为 10…所以 start(i+1) = start(i) * 10
- 数位数量计算公式:n 位数范围内的数位数量总和,比如一位数包含了 9 个 一位数,所以为 9*1;两位数包含了 90 个 两位数,所以为 90*2;三位数包含 900 个三位数所以为 900*3,所以规律其实就是 count = 9 * start * digit
- 接下来我们第一步先确定 n 对应的数是几位数,其实 n 对应的是数位数量,所以我们就让 n 不断减去 count,直到 n <= count,就能得到 n 对应几位数。
- 第二步我们确定一下他对应具体数字 num 为什么,将第一步计算完剩下的 n 整除 digit ,再加上起始值 start 就知道它对应哪个数,但是其实我们的推导过程都没去管 0 这个数,它也算一个数位,所以实际上 num 应该是 start + (n-1)/digit;
- 确定完了 num,同理还是用 n-1,让它对 digit 取余我们就知道他在这个数的第几位,所以把 num 转为 string,num.charAt((n-1)%digit) 就是最终对应的字符,转为数字即为最终结果
-
public int findNthDigit(int n) { long start = 1; int digit = 1; long count = 9; // 第一步 while(n > count){ n -= count; start*=10; digit++; count = start * digit * 9; } // 第二步 long num = start + (n-1)/digit; // 第三步 return Long.toString(num).charAt((n-1)%digit) - '0'; }
- 这是从 0 开始处理版本,不忽略 0,start 在观察一位数时为 0~9 的 0,之后才符合我们的递推公式,那么 count 也是在为一位数时为 10,之后符合递推公式,这样之后就不用 n-1,直接用 n 即可
-
public int findNthDigit(int n) { long start = 0; int digit = 1; long count = 10; while(n > count){ n -= count; if(start==0)start=10; else start*=10; digit++; count = start * digit * 9; } long num = start + n/digit; return Long.toString(num).charAt(n%digit) - '0'; }