剑指offer-----31、整数中出现1的次数

1、题目描述

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

2、分析

        首先最简单的就是暴力求解,对每一个数字来求解。另一种方法来自编程之美。详述如下:

        在分析之前,首先需要知道一个规律:

  • 从 1 至 10,在它们的个位数中,数字1出现了 1 次。
  • 从 1 至 100,在它们的十位数中,数字1出现了 10 次。
  • 从 1 至 1000,在它们的百位数中,数字1出现了 100 次。

        依此类推,从 1 至 10i,在它们右数第二位中,数字1出现了10 ^ (i - 1)次。

        对于 n = 2134,要找到从1 ~ 2134这2134个数字中所有1的个数。我们可以对2134进行逐位分析:

        (1)在个位上,从1~2130,包含213个10,因此数字1出现了213次,剩下的数字2131、2132、2133、2134中个位数上只有2131包含树脂字1,剩下的都不包含。所以个位数上的数字1的总数为213 + 1 = 214。

        (2)在十位上,从1 ~ 2100,包含了21个100,因此数字1出现了21 * 10 = 210次,剩下的数字从2101 ~ 2134,只有2110 ~ 2119这10个数字中十位的数字为1,所以十位上的数字1的总数为210 + 10 = 220。

        (3)在百位上,从1 ~ 2000,包含了2个1000,因此数字1出现了2 * 100 = 200次,剩下的数字从2001 ~ 2134,只有2100 ~ 2134这35个数字中的百位的数字为1,所以百位数上数字1的总数为200 + 35= 235。

        (4)在千位上,包含了0个10000,因此数字1出现了0 * 1000 = 0次,剩下的数字中只有1000 ~ 1999这1000个数字中的千位的数字为1,所以千位上的数字1的总数为1000。

        因此从1 ~ 2134这n个数字中,数字出现的总的次数为 214 + 220 + 235 +1000 = 1669。

        总结一下以上的步骤,可以得到这么一个规律:

        对于数字n,计算它的第i(i从1开始,从右边开始计数)位数上包含的数字1的个数:

       假设第i位上的数字为x的话,则

       1.如果x > 1的话,则第i位数上包含的1的数目为:(高位数字 + 1)* 10 ^ (i-1)  (其中高位数字是从i+1位一直到最高位数构成的数字)

       2.如果x < 1的话,则第i位数上包含的1的数目为:(高位数字 )* 10 ^ (i-1)

      3.如果x == 1的话,则第i位数上包含1的数目为:(高位数字) * 10 ^ (i-1) +(低位数字+1)   (其中低位数字时从第i - 1位数一直到第1位数构成的数字)

3、代码

//暴力求解
class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        if(n<1) return 0;
        int res=0;
        for(int i=1;i<=n;++i){
            res+=get1num(i);
        }
        return res;
    }
    int get1num(int n){
        int res=0;
        while(n!=0){
            if(n%10==1)
                ++res;
            n/=10;
        }
        return res;
    }
};

//第二种
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
    {
    if( n < 0)
        return 0;
    int i = 1;
    int high = n;
    int cnt = 0;
    while(high != 0)
    {
        high = n / pow(10 ,i);//high表示当前位的高位
        int temp = n / pow(10, i - 1);
        int cur = temp % 10;//cur表示第i位上的值,从1开始计算
        int low = n  - temp * pow(10, i - 1);//low表示当前位的低位
        if(cur < 1)
        {
            cnt += high * pow(10, i - 1);
        }
        else if(cur > 1)
        {
            cnt += (high + 1) * pow(10 ,i - 1);
 
        }
        else
        {
 
            cnt += high * pow(10, i - 1);
            cnt += (low + 1);
 
        }
        i++;
    }
    return cnt;
    }
    
    
};

猜你喜欢

转载自blog.csdn.net/zl6481033/article/details/93406150