整数中1出现的次数(从1到n整数中1出现的次数)剑指offer 面试题43

题目描述:

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

解题思路:

例如求解:1-21345之间的出现的1的个数;分段处理:1-1345;1346-21345。

1346-21345的最高位的1的个数:10000-19999 1的数量10^4个,如果最高位不是2,是1(数字为11345);则为1345+1。

剩下的四位当中1的个数:1346-11345  1的数量4*10^3,11346-21345 1的数量4*10^3。 规律最高位数值*位数减1*10^(位数减2)

1-1345 则递归调用函数即可求得

通过的C++代码:

#include <cstdlib>
class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
    {
        if(n <= 0)
            return 0;
        char strNum[50];
        sprintf(strNum,"%d",n);
        return numberOf1(strNum);
    }
    int numberOf1(const char * strNum)
    {
        if(!strNum || *strNum < '0' || *strNum > '9' || *strNum == '\0')
            return 0;
        int first = *strNum - '0';
        //strlen获取的是char*字符串的真实长度,不包括'\0';而sizeof()是变量声明后占用的字节数,不是实际长度
        unsigned int len = static_cast<unsigned int>(strlen(strNum));
        if(len == 1 && first == 0)
            return 0;
        if(len == 1 && first > 0)
            return 1;
        //假设数字是21345
        //numFirstDigit 是第一位为1的数目
        int numFirstDigit = 0;
        if(first == 1)
        {
            numFirstDigit = atoi(strNum+1)+1;
        }
        else if(first > 1)
            numFirstDigit = powerBase10(len - 1);
        //numOtherDigits 表示1346-21345除了第一位之外的1的位数
        int numOtherDigits = 0;
        numOtherDigits = first * (len-1) * powerBase10(len - 2);
        //numRecursive 表示1-1345的1的位数,递归的求解
        int numRecursive = 0;
        numRecursive = numberOf1(strNum + 1);
        return numFirstDigit + numOtherDigits + numRecursive;
    }
    int powerBase10(unsigned int len)
    {
        int result = 1;
        for(int i=0; i<len; ++i)
            result *= 10;
        return result;
    }
};

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章