题目描述
求出113的整数中1出现的次数,并算出1001300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。
思路
1.分两部分统计:(数字分为两段,如给定21345,则分为1-1345和1346-21345两段)
(1)对于第二段(1346-21345),
第一步统计1出现在最高位的次数(判断最高位是否大于1,若大于1,则次数为10** (字符串长度-1);若最高位为1,则次数为除最高位外 后几位+1)
第二步统计1出现在最高位之外其他位的情况
(2)对于第一段(1-1345),采用按照(1)中操作递归的方法统计1的次数
注:
Str+1应该是字符数组的指针指向次高位
C 库函数 int atoi(const char *str) 把参数 str 所指向的字符串转换为一个整数(类型为 int 型)
strlen() :计算字符串 str 的长度,直到空结束字符,但不包括空结束字符
static_cast (expr): 强制类型转换运算符
sprintf函数详解
代码
class Solution {
public:
int NumberOf1Between1AndN_Solution(int n)
{
//检验有效性
if(n <= 0)
return 0;
//书上初始化的字符数组为50位
char strN[20];
//将整数n转换为字符串
sprintf(strN, "%d", n);
return numberOf1(strN);
}
int numberOf1(const char* Str)
{
//检验有效性
if(!Str || *Str < '0' || *Str >'9' ||*Str == '\0')
return 0;
//取首位
int first = *Str - '0';
//计算长度并判断数字位数
unsigned int length = static_cast<unsigned int>(strlen(Str));
//数组是否为1位(非0与否)
if(first == 0 && length == 1)
return 0;
if(first > 0 && length == 1)
return 1;
//数字为多位
//如21345,划分两段1-1345 和 1346-21345,先统计第二段
//第一部分:计算1出现在最高位的情况,统计
//声明此种情况的次数
int numFirstDigit = 0;
if(first > 1)
numFirstDigit = powerBase10(length - 1);
//首位为1
else if(first == 1)
numFirstDigit = atoi(Str+1) + 1;
//第二部分:1出现在除最高位外其他几位的情况
//声明一个变量记录此种情况的次数
int numOtherDigit = first * (length - 1) * powerBase10(length - 2);
//第三部分:统计1-1345
//声明记录次数的变量
int numRecursive = numberOf1(Str+1);
return numFirstDigit + numOtherDigit + numRecursive;
}
//计算10的次幂
int powerBase10(unsigned int n)
{
int result = 1;
for(int i = 0; i < n;++i)
result *= 10;
return result;
}
};