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