您的位置:首页 > Web前端

剑指Offer学习总结-从1到n整数中1出现的次数

2018-01-23 21:37 316 查看

剑指Offer学习总结-从1到n整数中1出现的次数

本系列为剑指Offer学习总结,主要是代码案例的分析和实现:

书籍链接:http://product.dangdang.com/24242724.html

原作者博客:http://zhedahht.blog.163.com/blog/static/254111742011101624433132/

原作者博客链接有完整的项目代码下载。

从1到n整数中1出现的次数

题目

题目:输入一个整数n,求从1到n这n个整数的十进制表示中1出现的次数。例如输入12,从1到12这些整数中包含1的数字有1,10,11和12,1一共出现了5次。

第一眼看到的解法:

累加 1 到 n 中每个整数 1 出现的次数。 求每个整数的1的个数,我们可以每次

通过对 10 求余数判断整数的个位数字是不是 1。

如果这个数字大于 10, 除以 10 之后再判断个位数字是不是 1。

int NumberOf1Between1AndN_Solution1(unsigned int n)
{
int number = 0;

for(unsigned int i = 1; i <= n; ++ i)
number += NumberOf1(i);

return number;
}

int NumberOf1(unsigned int n)
{
int number = 0;
while(n)
{
if(n % 10 == 1)
number ++;

n = n / 10;
}

return number;
}


分析规律解法:

找规律的办法,其实也是有简单到复杂,由一般到特殊,通过举例分析的办法来进行。

如果希望不用计算每个数字的1的个数,那就只能去寻找1在数字中出现的规律了。为了找到规律,我们不妨用一个稍微大一点的数字如21345作为例子来分析。

把数字分为2段,一段是1~1345,另一段是1346~21345.

(1)1345~21345中,万位上出现1的数字在10000~19999中,有10^4个。如果n的长度为length,则共有10^(length-1)次。

(2)如果首位数字等于1,比如从10000~12345,则最高位出现1的次数为2345+1=2346次,即共有atoi(strN+1)+1次。

(3)除了第一位的数之外,其他位上有1的次数:由于最高位是2,我们再把1346~21345分成2段,1346~11346,11236~21346,每一段剩下的4位数字中,选择其中一位是1,其余三位可以在0~9这10个数字中任选,

因此根据排序组合的原则,总共出现的次数是2*4*10^3=8000次

所以有2*10^3次。即共有first*(length - 1)*10^(length-2)次。

(4)1~1345中1的次数,就是21345中除去首位之后的次数。迭代求得。

int NumberOf1Between1AndN_Solution2(int n)
{
if(n <= 0)
return 0;

char strN[50];
sprintf(strN, "%d", n);

return NumberOf1(strN);
}

int NumberOf1(const char* strN)
{
if(!strN || *strN < '0' || *strN > '9' || *strN == '\0')
return 0;

int first = *strN - '0';
unsigned int length = static_cast<unsigned int>(strlen(strN));

if(length == 1 && first == 0)
return 0;

if(length == 1 && first > 0)
return 1;

// 假设strN是"21345"
// numFirstDigit是数字10000-19999的第一个位中1的数目
int numFirstDigit = 0;
if(first > 1)
numFirstDigit = PowerBase10(length - 1);
else if(first == 1)
//这里指针+1则指向了下一位 也就是1345
numFirstDigit = atoi(strN + 1) + 1;

// numOtherDigits是01346-21345除了第一位之外的数位中1的数目
int numOtherDigits = first * (length - 1) * PowerBase10(length - 2);
// numRecursive是1-1345中1的数目
int numRecursive = NumberOf1(strN + 1);

return numFirstDigit + numOtherDigits + numRecursive;
}

int PowerBase10(unsigned int n)
{
int result = 1;
for(unsigned int i = 0; i < n; ++ i)
result *= 10;

return result;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: