剑指Offer——数字序列中某一个位数

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

方法一:从0开始进行枚举。每枚举一个数字的时候,求出该数字是几位数,然后把该数字的位数与前面所有数字的位数进行累加。如果位数之和小于或等于n,继续枚举下一个。当大于n的时候,那么n位数字就一定在这个数字里,然后在这个数字中找出对应的一位。

方法二:找出规律,跳过某些数字。例如序列的第1001位是什么?序列前的0~9这10个数字只有1位数,直接跳过。然后在后面的序列中找第991(1001-10)位的数字。然后接下来的180位数字是10~99的两位数,因为991>180,继续跳过。在后面找811(991-180)位的数字。下来2700位是100~999的三位数,由于811<2700,所以第811是某个三位数中的一位,811=270*3+1,所以是从100开始的第270个数字即370的中间一位,也就是7。

class Solution {
     public int findNthDigit(int n) {
        if(n<0){
            return 0;
        }
        //位数
        int digits=1;
        while(true){
            //找出这个位数所拥有的数字个数
            long numbers=count(digits);
            //如果n在这个范围,进行查找
            if(n<numbers*digits){
                return digitsIndex(n,digits);
            }
            //否则跳过
            n-=digits*numbers;
            digits++;
        }
    }
    //统计位数所拥有的数字个数
    private  int count(int digits){
        if(digits==1){
            return 10;
        }
        int count=(int)Math.pow(10,digits-1);
        return 9*count;
    }
    //查找这个数
    private  int digitsIndex(int index,int digits){
        //报错是因为超出了范围
        //起始数+这个数在位于范围内的位置
        long number=beginNumber(digits)+(long)index/digits;
        int indexFromDigits=digits-index%digits;
        for(int i=1;i<indexFromDigits;++i){
            number=number/10;
        }

        return new Long(number%10).intValue();
    }

    //找到这个位数的起始数
    private static long beginNumber(int digits){
        if(digits==1){
            return 0;
        }
        return (long)Math.pow(10,digits-1);
    }
}

注意的是:如果给的n位数大的话,再求位数拥有的个数和起始数的时候,会因为超出int的存储范围进行错误的运算。为了保证数据的 正确性,要注意使用

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值