【JZ-44】数字序列中某一位的数字(数学)

题目

在这里插入图片描述

算法思路

与【JZ-43】一样,重点在于寻找规律。
参考
将101112…中的每一位,即1,0,1,1,1,2,…称为数位,记为 n n n
将10,11,12,…称为数字,记为 n u m num num
将数字包含的数位个数称为位数,记为 d i g i t digit digit,例如数字13的位数为2;
将每 d i g i t digit digit 位数的起始数字记为 s t a r t start start,结束数字记为 e n d end end,例如 d i g i t digit digit 为2时, s t a r t start start等于10, e n d end end等于99。

数字范围位数数字个数数位个数
1~9199
10~99290180
100~99939002700
s t a r t start start~ e n d end end d i g i t digit digit9* s t a r t start start9* s t a r t start start* d i g i t digit digit

故问题的求解可以分为三个部分:

  1. 确定 n n n 所在的数字的位数,即确定 d i g i t digit digit
  2. 确定 n n n 所在的数字,即确定 n u m num num
  3. 确定 n n n 对应数字 n u m num num 中的哪一数位

1. 确定 digit:

d i g i t digit digit 下数位个数 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 依次减去一位数、两位数、…的 c o u n t count count,直到 n n n 小于等于当前 d i g i t digit digit 下的数位个数 c o u n t count count

int digit = 1;
int start = 1;
int count = 9;
while(n > count){
    n -= count;
    start *= 10;
    digit += 1;
    count = 9 * start * digit;
}

则循环结束后,所求的数位一定在某个 d i g i t digit digit 位数中,且为从 s t a r t start start 开始的第 n n n 个数位。

2. 确定 num:

显然有num = start + (n - 1) / digit;,例如 d i g i t digit digit 为 2 时, s t a r t start start 等于 10,数位和数字的对应关系为:

10111213
n n n12345678
( n − 1 ) / 2 (n - 1) / 2 (n1)/200112233

3. 确定对应 num 中的哪一数位

到这里我们已知所求的数位在 d i g i t digit digit 位的数字 n u m num num 中,先将数字 n u m num num 转换为字符串 s s s,显然有 res = s[(n - 1) % digit]
例如 d i g i t digit digit 为 2 时, s t a r t start start 等于 10,数位和数字的对应关系为:

10111213
n n n12345678
( n − 1 ) % 2 (n - 1) \% 2 (n1)%201010101

具体代码

class Solution {
    public int findNthDigit(int n) {
        if(n == 0)return 0;
        int digit = 1;
        long start = 1;
        long count = 9;//有可能会超出int的范围
        //1.确定n所在的数字的位数
        while(n > count){
            n -= count;
            start *= 10;
            digit += 1;
            count = 9 * start * digit;
        }
        //2.确定n所在的数字
        long num =  start + (n - 1) / digit;
        //3.确定n对应数字num中的哪一数位
        String s = Long.toString(num);//先将数字num转换为字符串
        return s.charAt((n - 1) % digit) - '0';//利用ASCII码相减得到该位置上字符的十进制值
    }
}

注意:

  1. 要考虑变量是否会超出 int 的范围
  2. 关于最后字符串相减,s.charAt(i)-'0',两个字符相减实际上是ASCII码相减,这样得到的结果才会是 s 中第 i 个字符的十进制值

最后确定结果的时候也可以不用把数字转为字符串,即:

        int index = (n - 1) % digit;
        while(index < (digit - 1)){
            num /= 10;
            digit--;
        }
        return num % 10;

复杂度分析

  • 时间复杂度: O ( l o g n ) O(logn) O(logn) n n n 所在的数字的位数 d i g i t digit digit最大为 O ( l o g n ) O(logn) O(logn),第一步的时间开销为 O ( l o g n ) O(logn) O(logn),第二步的时间开销为 O ( 1 ) O(1) O(1),第三步将数字转换为字符串的时间开销为 O ( l o g n ) O(logn) O(logn)
  • 空间复杂度: O ( l o g n ) O(logn) O(logn)。将数字转换为字符串额外占用了 O ( l o g n ) O(logn) O(logn)的空间。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值