Loading

Medium | LeetCode 400 | 剑指 Offer 44. 数字序列中某一位的数字

Medium | LeetCode 400 | 剑指 Offer 44. 数字序列中某一位的数字

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

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

示例 1:

输入:n = 3
输出:3

示例 2:

输入:n = 11
输出:0

限制:

  • 0 <= n < 2^31

首先观察数字的规律如下:

确定某一位的数字的基本步骤如下:

根据以上分析,可将求解分为三步:

  1. 确定 n 所在 数字 的 位数 ,记为 digit ;

    将此数字依次减去9, 90, 900, 9000, 直到减不够为止, 减不够时剩下来的数的位数就是当前所要确定的数字的位数。比如n = 150, 减去99位, 还剩51位, 减900减不够。那么n所在数字的数就是一个三位数。

  2. 确定 n 所在的 数字 ,记为 num ;

    第一步得到n所在数组是一个三位数, 并且剩下51, 所以当前数是 51 % 3 = 27个数, 则当前数字是 100 + (51 % 3) - 1 = 126;
    还有一种计算方法:100 + (51 - 1) % 3 = 126, 这两种计算方法结果都是126, 那种方法对?还是都对?
    答案是: num = start + (n - 1) / digit 这种方法是对的, 另一种是错的。为什么?因为要用除法对每三个数分一组, 比如1,2,3分一组, 4,5,6, 分一组, 最后一个数的除的数与前面数字的除得数是不一样的。如果先做减1的处理, 0,1,2分一组, 3,4,5分一组, 这样就能够通过除法的方式进行分组了。

  3. 确定 n 是 num 中的哪一数位,并返回结果

    第二步的结果已经得到了是第多少个数字, 我们求得的结果是126。我们知道按三个三个分组, 51处在分组的最后面一位, 也就是126的最低位。3个3个分组, 然后取分组里某一位, 我们立马想到的是模运算。51%3 = 0, 显得不对。所以在进行模运算计算位数时, 也应该遵循减1的方法, 让下标从0开始。也就是index = (n - 1) % digit;

以上三个问题解决了, 最终的代码就顺理成章的出来了。

public int findNthDigit(int n) {
    int digit = 1;
    long start = 1;
    long count = 9;
    // 第一步: 确定n所在数字位数
    while(n > count) { // 最终减不够的时候跳出循环
        n -= count;
        // 位数和这个位数的最小值start同步增加
        digit++;
        start *= 10;
        // count是这个位数的所有数字长度总和, 比如2位数有90个, 总长为180
        count = digit * start * 9; 
    }
    // 第二步:确定所在的数字
    long num = start + (n - 1) / digit ;
    // 第三步:确定n在数字的第几位
    int index = (n - 1) % digit;
    return String.valueOf(num).charAt(index) - '0';
}
posted @ 2021-01-14 22:42  反身而诚、  阅读(89)  评论(0编辑  收藏  举报