剑指offer刷题- 数字序列中某一位的数字
Posted 王六六的IT日常
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了剑指offer刷题- 数字序列中某一位的数字相关的知识,希望对你有一定的参考价值。
数字序列中某一位的数字
题目描述:数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。
参考:K神题解
解题思路:
- 将 101112... 101112... 101112...中的每一位称为数位,记为 n n n。
- 将 10 , 11 , 12 , . . . 10,11,12,... 10,11,12,...称为数字,记为 n u m num num。
- 数字 10 10 10是一个两位数,称此数字的位数为 2 2 2,记为 d i g i t digit digit。
- 每
d
i
g
i
t
digit
digit位数的起始数字(即:
1
,
10
,
100
,
.
.
.
1,10,100,...
1,10,100,...),记为
s
t
a
r
t
start
start。
各 d i g i t digit digit 下的数位数量 c o u n t count 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 n n的位数 d i g i t digit digit
- 确定 n n n所在的数字 n u m num num
- 确定 n n n是 n u m num num中的哪一位数,返回结果
1.确定 n n n为几位数
循环执行
n
n
n 减去 一位数、两位数、… 的数位数量
c
o
u
n
t
count
count,直至
n
≤
c
o
u
n
t
n \\leq count
n≤count时跳出循环。
由于
n
n
n 已经减去了一位数、两位数、… 、(
d
i
g
i
t
−
1
digit - 1
digit−1)位数的数位数量
c
o
u
n
t
count
count,因此此时的
n
n
n 是从起始数字
s
t
a
r
t
start
start开始计数的。
举例:
int digit = 1; //一位数
long start = 1;//一位数从1开始
long count = 9; //一位数有9个数字
while (n > count)
n -= count;
digit++;
start *= 10;
count = digit * start * 9;
2. 确定 n n n 所在的数字 n u m num num
所求数位 在从数字 s t a r t start start 开始的第 [ ( n − 1 ) / d i g i t ] [(n - 1) / digit] [(n−1)/digit]个 数字 中( s t a r t start start 为第 0 个数字)。
这里取
n
−
1
n-1
n−1的原因是:当
n
n
n 对应
n
u
m
num
num 中的最后一位时,不会由于进位,错误的寻找到下一个数字。
long num = start + (n - 1) / digit;
3. 确定 n n n 在 n u m num num 的哪一数位
所求数位
r
e
s
res
res 为数字
n
u
m
num
num 的第
(
n
−
1
)
%
d
i
g
i
t
(n−1)\\%digit
(n−1)%digit 位( 数字的首个数位为第 0 位)
这里取n-1使得num中各位的位置坐标从左到右从0开始增加,即
0
,
1
,
.
.
.
.
,
(
d
i
g
i
t
−
1
)
0,1,....,(digit-1)
0,1,....,(digit−1),更容易理解。
s = str(num) //将num转化为 string
//获得 num 的 第 (n - 1) % digit 个数位,并转化为 long
res = long(s[(n - 1) % digit])
res = Long.toString(num).charAt((n - 1) % digit) - '0';
class Solution
public int findNthDigit(int n)
int digit = 1;
long start = 1;
long count = 9;
while (n > count) // 1.
n -= count;
digit += 1;
start *= 10;
count = digit * start * 9;
long num = start + (n - 1) / digit; // 2.
return Long.toString(num).charAt((n - 1) % digit) - '0'; // 3.
class Solution
public int digitAtIndex(int n)
//1.确定是几位数
//i表示是几位数,s表示该位数的数有多少个,如1位数9个,2位数的有90个,3位数900个...
//base表示一个几位数的起点,如一位数起点是1,二位数起点是10...
//当输入的n是int的最大值时,位数为9位,此时s *= 10执行九次的话会int越界的,故用long接收
long i = 1,s = 9,base = 1;
while(n > i * s)
n -= i * s;
i++;
s *= 10;
base *= 10;
//2.确定是几位数的第几个数,求出这个数数值num
// 已经知道了序列的第n位是一个几位数中的某一位,那到底是哪一个几位数呢
// (n + i - 1) / i 为 n/i 的上取整公式
long num = base + (n + i - 1) / i - 1;
//3.确定属于那个数的第几位
//求余数即可
//r = 0 表示是最后一位(也就是 i,几位数就是几),r != 0,则r是几就是第几位
long r = n % i == 0 ? i : n % i;
//取出num的第r位,去掉后面的i - r位即可
//如12345的第三位,后面还有两位45,我们将这两位去掉才好取出顺数的第三位
for(int j = 1; j <= i - r;j++)
num /= 10;
return (int)num % 10;//取出现在的个位就是我们的结果
start的值应该一直小于n的值,n为int,start应该用int的范围就够了,只是count的值在第一步最后一次循环时可能会超限,应该用long。最后确定结果的时候也可以不用转为字符数组。
public int findNthDigit(int n)
if(n==0) return 0;
//由于是n=0时对应开始的0,这里不需要进行减操作n--;,但是如果n=1对应开始的0则需要减操作
//排除n=0后,后面n从1开始。
int digit = 1;
int start = 1;
long count = 9; //count的值有可能会超出int的范围,所以变量类型取为long
while(n>count)//不能带=号,此时n从1开始,n=count时,属于上一个循环的最后一个数字
n=(int)(n-count);//这里(int)不能省略
digit++;
start = start*10;
count = (long)start*9*digit;
//这里的long不能省略,否则,会先按照int类型进行计算,然后赋值给long型的count,超过int大小限制时,会出现负数
int num = start + (n-1)/digit;
int index = (n-1)%digit;//index最大取digit-1,即此时num坐标从左到右为0,1,...,digit-1,共digit位
while(index<(digit-1))
//最后的结果是num中的第index个数字,index从左到右从0开始递增,考虑到踢出右侧末尾的数字比较简单,我们从右侧开始依次踢出数字
num = num/10;
digit--;
return num%10;//此时num的右侧末尾数字即为结果
以上是关于剑指offer刷题- 数字序列中某一位的数字的主要内容,如果未能解决你的问题,请参考以下文章