剑指 Offer 44. 数字序列中某一位的数字

这篇博客介绍了如何计算数字序列0123456789101112131415…中任意第n位对应的数字。通过分析序列规律,确定数字的长度和位置,然后计算具体数值。给出了详细的代码实现,包括求解数字长度、确定所在数及位置,最后获取目标位的数字。
摘要由CSDN通过智能技术生成

题目描述:

数字以0123456789101112131415…的格式序列化到一个字符序列中。在这个序列中,第5位(从下标0开始计数)是5,第13位是1,第19位是4,等等。
请写一个函数,求任意第n位对应的数字。

求解

为了方便我们先不考虑0,1是第一位数。
我们先把每个数字单独考虑,如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 … 99 100 101 102 … 999 …
对于长度位1的数,它们的各个位上的数字处于[ 1 1 1, 1 ∗ 9 ∗ 1 0 0 1*9*10^0 19100]这个范围内,对于长度为2的数字上的每一位他们处于 1 ∗ 9 ∗ 1 0 0 + 1*9*10^0 + 19100+[ 1 1 1, 2 ∗ 9 ∗ 1 0 1 2*9*10^1 29101]这个范围内。以次类推,我们可以得到长度为k>1的数字上的每一位的处于 1 ∗ 9 ∗ 1 0 0 + 1 ∗ 9 ∗ 1 0 1 + . . . + 1 ∗ 9 ∗ 1 0 ( k − 2 ) + 1*9*10^0 + 1*9*10^1 +...+1*9*10^{(k-2)}+ 19100+19101+...+1910(k2)+ [ 1 1 1, k ∗ 9 ∗ 1 0 ( k − 1 ) k*9*10^{(k-1)} k910(k1)]。
对于给定的n,先求它所处的数是几位数(len),我们可以不断的减去 1 ∗ 9 ∗ 1 0 0 1*9*10^0 19100 1 ∗ 9 ∗ 1 0 1 1*9*10^1 19101,直到 n < = 1 ∗ 9 ∗ 1 0 ( l e n − 1 ) n <= 1*9 *10 ^{(len - 1)} n<=1910(len1)。于是给出如下代码:

int len = 1;
while(len * 9 * Math.pow(10, len - 1) < n){
	n -= len * 9 * Math.pow(10, len - 1);
	len++;
}

使用以上代码我们可以求得n所处的位的数的长度,注意此时n已经不是从1开始的第n位数,而是从 1 0 l e n − 1 10^{len-1} 10len1的1开始的第n位数。
我们先确定在n在第几个(x)长度为len的数上,使用如下代码即可

	int x = n % len == 0 ? n/len: n/len + 1;

知道在n在第x个长度为len的数上,也就知道了n所在的数的值(val),和n在第x个数上的哪个(t)位置上。

	int val = Math.pow(10, len -1) + x - 1;
	int t = n - len*(x - 1);

求出val上的第t位即可(从高到低)。

	int ret = (val%Math.pow(10, len - t + 1))/Math.pow(10, len - t);

下面是完整代码,对于n位0的情况同样适用

    public int findNthDigit(int n) {
    	//求n所在的数的长度
        int len = 1;
        while(len * 9 * Math.pow(10, len - 1) < n){
	        n -= len * 9 * Math.pow(10, len - 1);
	        len++;
        }
        //求n在长度位len的数的第几个数上,如果n%len = 0,说明它就在n/len这个数上,否则在后面一个数上。
        int x = n % len == 0 ? n/len: n/len + 1;
        //求第x个数的数值
        int val = (int)Math.pow(10, len -1) + x - 1;
        //求n在第x个数的哪个位上
	    int t = n - len*(x - 1);
	    //求val的第t位上的值
        int ret = (val%(int)Math.pow(10, len - t + 1))/(int)Math.pow(10, len - t);
        return ret;
    }
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值