44. 数字序列中某一位的数字

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

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

请写一个函数,求任意第n位对应的数字。

示例 1:

输入: n = 3
输出: 3

示例 2:

输入: n = 11
输出: 0

限制:

0 <= n < 2^31
注意:本题与主站 400 题相同:https://leetcode-cn.com/problems/nth-digit/

解题思路

首先我们知道的是,1 位数有 10 个,2 位数有 90 个,3 位数有 9 * 100 个,4 位数有 9 * 1000 个,以此类推,如下表

数字范围数量位数占多少位
1 ~ 9919
10 ~ 99902180
100 ~ 99990032700
  1. 假如我们需要求的是序列的第1001位是什么,我们可以发现1001 > 9,所以第1001位肯定在1~9这九位数字之后,接下来我们又发现(1001 - 9) > 180,所以第1001位也不可能是一个两位数中的某位,而(1001 - 9 - 180)< 2700,因此可以断定序列的第1001位是一个三位数中的某一位。

  2. 现在已经知道了序列的第1001位是一个三位数中的某一位,那到底是哪一个三位数呢,很简单,计算方法为(1001 - 9 - 180)/ 3向上取整,即100 + ((1001 - 9 - 180 + 3 - 1)/ 3 ) - 1= 370。看下方注1中的上取整公式即可。

  3. 好的,现在也知道了它是属于370的某位的,那到底是哪一位,求余就好了(1001 - 9 - 180)% 3 = 2;所以答案是370中的第二位,即7

注1: n / i上取整的公式为(n + i - 1)/ i
原因:

  • n能整除i时,则(i - 1) / i = 0;
  • n不能整除i时,由于n是整数,则最少也会余1,所以(i - 1 + 大于1小于i的数) / i = 1,实现了上取整。

注2:题目中第几位是从0开始计数的,即第0位,第1位,第2...,而我们上面例子刚好也是从0开始计数,即0就是第0位,1就是第1位,也就是说,题目中表达的第1001位指的就是我们表格中从1开始计数的第1001位。

总结上述过程为:

  • 确定序列的第n位应该是一个几位数中的某一位,比如是三位数
  • 确定是几位数的第几个数,然后确定具体数值,比如是三位数的第271 个数,则数值是100 + 271 - 1 = 370
  • 确定属于那个数的第几位,比如是370的第二位,即7

时间复杂度: O ( l o g 10 n ) O(log_{10}n) O(log10n) 也即 O ( l o g n ) O(logn) O(logn)

总的时间复杂度即三步操作的时间复杂度

int 的范围 2 ∗ 1 0 9 2∗10^9 2109,所以最多是 10 位数,因此第一步操作的时间最多是 l o g 10 n = 10 log_{10}n = 10 log10n=10次,是 O ( 1 ) O(1) O(1) 的时间复杂度,第二步除法向上取整,也是 O ( 1 ) O(1) O(1) 的,第三步求是第几位数字是 O ( l o g 10 n ) O(log_{10}n) O(log10n) 的,因为在二进制表示中取某一位可以每次右移1 位(即除以 2),所以是 O ( l o g 2 n ) O(log_2n) O(log2n)级别的,同理在十进制中取某一位可以每次右移1 位(即除以10),所以是 O ( l o g 10 n ) O(log_{10}n) O(log10n) 级别的

Java代码

class Solution {
    public int findNthDigit(int n) {
        //1.第n位是一个几位数中的某一位
        //i表示是几位数,s表示该位数的数有多少个,如1位数9个,2位数的有90个...
        //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.看它是几位数的第几个数,然后就可以知道它的数值了(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;//取出现在的个位就是我们的结果
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值