题目描述:
求出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;
}
};