《剑指offer》---------整数中1出现的次数

题目

求出1-13的整数中1出现的次数,并算出100-1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

方法一

暴力法:挨个遍历求出每个数中一的个数,还是比较好理解的,第一个函数就是求当前数中的1的个数,下面的函数依次遍历即可。

class Solution {
public:
    int Number( int n)
    {
        int number=0;
        while(n)
        {
            if(n%10==1)
                ++number;
            n=n/10;
        }
        return number;
    }
    int NumberOf1Between1AndN_Solution(int n)
    {
     int number=0;
         
        for(int i=1;i<=n;i++)
        {
            number+=Number(i);
        }
        return number;
    }
};

方法二

既然遍历法算法复杂度较高,那么就要从数字的规律中去寻找解决办法了,当然我想不出来,看了很多篇博客终于发现一篇不错的解释:就是将数n的每一位拿出来单独讨论,每一位的值计做weight,看看各自位的1的个数.

1.个位

当数从1到n依次递增的时候,我们发现个位的数字weight从0-9在不断循环,每出现一次0-9,个位就会有个1,那么我们知道个位从0-9循环多少次是不是就相当于知道个位出现多少次1了,那么怎么知道0-9的玄幻次数呢? 这取决于n的高位是多少,如图:
在这里插入图片描述
这里n=534,对于个位来说高位就是它前面这几位的数字,就是说534的个位从0-9循环了53次,大家想想是不是这么回事,每循环一次个位的1出现一次,所以出现了53次,我们把循环次数记为round,再来看weight值为4,说明第54循环开始了!但是它只从0走到了4,但是这里面也包含一次1啊,所以必须再加1啊,计次数为count,那么:
           count=round+1=53+1=54;
这是个位数weight大于0的情况,如果正好等于0,那么就不用加一,说明刚好进行了53次循环,即n=530是:
          count=round=53;

2.十位

对于10位,还是可以按照个位的方式统计1的次数,如图;
在这里插入图片描述
不同之处就是 当数从1开始递增式时每增加10个,weight才加一,也就是满10进一,因为此时讨论的是10位,所以weight落在10位上,大家不要搞混·,所以当weight从0-9递增时,(记住这里是10位的递增),1出现了10次!不懂?其实说白了就是当weight为1时计数,例如110,111,11,2…119,这里10位上1的个数为10,这是weight为1的时候,当weight从2-9递增时都不会出现1,这回你懂了么,那么weight要从0-9循环几次相对应的1的个数就是 (循环次数10),
count=round * 10
再来看weight具体数值的影响:
当weight大于1时,当n=534时·,说明已经循环5次了,第六次循环也开始了weight从0走到了3,这其中也包含1,1的个数为10;所以1的总个数为:
count=round * 10+10=5
10+10=60;
当weight等于0时 即n=504,说明第六次循环到0就停止了,
count=round * 10=50;
当weight等于1即n=514时,第6次出现了多少次1呢,这与个位数有关,设个位数为former,则1出现了former+1次
count=round * 10+former+1=5*10+4+1=55;

3.更高为位

与10位一致。

4) 总结

将n的各个位分为两类:个位与其它位。
对个位来说:

若个位大于0,1出现的次数为round1+1
若个位等于0,1出现的次数为round
1
对其它位来说,记每一位的权值为base,位值为weight,该位之前的数是former,举例如图:

则:
若weight为0,则1出现次数为roundbase
若weight为1,则1出现次数为round
base+former+1
若weight大于1,则1出现次数为rount*base+base
比如:

534 = (个位1出现次数)+(十位1出现次数)+(百位1出现次数)=(531+1)+(510+10)+(0100+100)= 214
530 = (53
1)+(510+10)+(0100+100) = 213
504 = (501+1)+(510)+(0100+100) = 201
514 = (51
1+1)+(510+4+1)+(0100+100) = 207
10 = (11)+(010+0+1) = 2

代码

class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
      int round=n;
      int count=0;
      int base=1;
        while(round)
        {
          int weight=round%10;
            round=round/10;
            count+=round*base;
            if(weight==1)
                count+=(n%base)+1;
            if(weight>1)
                count+=base;
            base*=10;
        }
        return count;
    }
};
发布了47 篇原创文章 · 获赞 2 · 访问量 1451

猜你喜欢

转载自blog.csdn.net/weixin_42076938/article/details/103843030
今日推荐