1 题目描述
数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。
示例1:
输入:n = 3
输出:3
示例2:
输入:n = 11
输出:0
2 解题思路
- 将101112…中的每一位称为数位,记为n;
- 将10,11,12,…称为数字,记为num;
- 数字10是一个两位数,称此数字的位数为2,记为digit;
- 每digit位数的起始数字(即:1,10,100,…),记为start。
观察上表,可推出各digit下的数位数量count的计算公式:
c o u n t = 9 × s t a r t × d i g i t count=9\times start \times digit count=9×start×digit
根据以上分析,可将求解分为三步:
- 确定n所在数字的位数,记为digit;
- 确定n所在的数字,记为num;
- 确定n是num中的哪一数位,并返回结果。
1. 确定所求数位的所在数字的位数
如下图所示,循环执行n减去一位数、两位数、…的数位数量count,直至 n ≤ c o u n t n \leq count n≤count时跳出。
由于n已经减去了一位数、两位数、…、(digit-1)位数的数位数量count,因而此时的n是从起始数字start开始计数的。
int digit = 1, start = 1, count = 9;
while (n > count) {
n -= count;
start *= 10;
digit += 1;
count = 9 * start * digit;
}
**结论:**所求数位1)在某个digit位数中;2)为从数字start开始的第n个数位。
2. 确定所求数位所在的数字
如下图所示,所求数位在从数字start开始的第[(n-1)/digit]个数字中(start为第0个数字)。
num = start + (n - 1) / digit;
结论:
所求数位在数字num中。
3. 确定所求数位在num的哪一数位
如下图所示,所求数位为数字num的第 ( n − 1 ) % d i g i t (n-1) \% digit (n−1)%digit位(数字的首个数位为第0位)。
s = Integer.toString(num) //转化为String
res = (int)s[(n-1)%digit]; //获得num的第(n-1)%digit个数位,并转化位int
结论: 所求数位是res。
class Solution {
public int findNthDigit(int n) {
int digit = 1;
long start = 1, count = 9;
while (n > count) {
n -= count;
start *= 10;
digit += 1;
count = 9 * digit * start;
}
long num = start + (n - 1) / digit;
return Long.toString(num).charAt((n - 1) % digit) - '0';
}
}
复杂度分析:
- 时间复杂度 O(logn) : 所求数位 n 对应数字 num 的位数 digit 最大为 O(logn) ;第一步最多循环 O(logn) 次;第三步中将 num 转化为字符串使用 O(logn) 时间;因此总体为 O(logn) 。
- 空间复杂度 O(logn) : 将数字 num 转化为字符串 str(num) ,占用 O(logn) 的额外空间。