剑指offer44:数字序列中某一位的数字

1.暴力

想必很多人的第一反应都是,就硬数啊,设置一个大一点的整型变量k,long或者long long啥的,由于他的n应该是在unsigned int里边,所以我们对k进行递增,对每个k,用另外一个变量累加位数,知道遇到对的n的位置,其实这种想法挺好的,至少是个可实现的思路对吧,但是还有更好的方法。

2.分析数字的位数

来点《剑指offer》的分析:

来个栗子,如果把n=1001给你,你会怎么做?显然,不会这么暴力,你会想,0-9有10个,这是1位的,一共10X1=10个位数,1001-10=991,然后算两位的10-99,90X2=180个数字,991-180=811,然后算三位的100-999,900X3=2700,啊811<2700,那么我们要找的就在三位中,那怎么去找呢,我们要找的是不是三位数中的数字序列中的第811个,自然,我们会想到求他是第几个三位数,811/3=270,好家伙,这不就求出来了么,100+270(偏移)=370,而我们要注意811%3=1,意味着我们要求的是中间的那个数字,也就是7。

一点细节:会有人想为啥100+270么,我一开始是卡了一会,因为这不是整除么,讲道理应该是下一位的中间一位才对啊,然后后来我直接把这个偏移当成一个类似数组下标的东西,100对应下标0,101对应下标1,那么370对应下标270。书中写到370是第270个数,总感觉有点歧义啥的......

不过有的老哥知道分析不知道写出来代码的......maybe,回顾一下我们干了什么,我们需要一个记录位数的变量,一个求取对应位数下一共有多少个数字的功能函数,我们还需要一个计算数字的函数。

而我们要做的主干操作就是:

1.求取当前位数digits下的数字总数count

2.如果数字序列总数count*digits>n,求对应的数字返回

3.n-=count*digits

4.digits++

代码如下所示:

class Solution {
public:
    int findNthDigit(int n) {
        int digits=1;//数字位数
        while(true)
        {
            // int count=countOfIntegers(digits);
            long long count=countOfIntegers(digits);
            if(n<count*digits)
            {
                return findNum(n,digits);
            }
            n-=count*digits;
            ++digits;
        }
        return -1;
    }
    //求对应位数下有多少数字
    long long countOfIntegers(int k)
    {
        if(k==1) return 10;
        long long count=pow(10,k-1);
        return 9*count;
    }
    //求对应数字
    //index是数字序列索引
    //digits是位数
    int findNum(int index,int digits)
    {
        int number=beginNum(digits)+index/digits;
        int indexFromRight=digits-index%digits;
        for(int i=1;i<indexFromRight;++i)
        {
            number/=10;
        }
        return number%10;
    }
    //求对应位数下最开始的那个数
    int beginNum(int digits)
    {
        if(digits==1) return 0;
        return pow(10,digits-1);
    }
};

结果如下所示:

 这里有一点细节就是count要是longlong的,换成int的话会在count*digits的时候爆掉,可能是这个时候他们两个相乘还是int的,已经装不下了啥的......

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值