- 1、本文档共13页,可阅读全部内容。
- 2、原创力文档(book118)网站文档一经付费(服务费),不意味着购买了该文档的版权,仅供个人/单位学习、研究之用,不得用于商业用途,未经授权,严禁复制、发行、汇编、翻译或者网络传播等,侵权必究。
- 3、本站所有内容均由合作方或网友上传,本站不对文档的完整性、权威性及其观点立场正确性做任何保证或承诺!文档内容仅供研究参考,付费前请自行鉴别。如您付费,意味着您自己接受本站规则且自行承担风险,本站不退款、不进行额外附加服务;查看《如何避免下载的几个坑》。如果您已付费下载过本站文档,您可以点击 这里二次下载。
- 4、如文档侵犯商业秘密、侵犯著作权、侵犯人身权等,请点击“版权申诉”(推荐),也可以打举报电话:400-050-0827(电话支持时间:9:00-18:30)。
查看更多
编程之美 1的数目
写书评,赢取 《编程之美--微软技术面试心得》/BCZM.asp
1 的数目
给定一个十进制正整数 N ,写下从1 开始,到 N 的所有整数,
然后数一下其中出现的所有“1”的个数。
例如:
N= 2 ,写下1 ,2。这样只出现了 1 个“ 1”。
N= 12 ,我们会写下1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12。这样,1
的个数是 5。
问题是:
1. 写一个函数f (N ),返回1到N 之间出现的“1”的个数,比如f (12 )
=5。
2. 在32位整数范围内,满足条件“f (N )= N”的最大的N 是多少?
写书评,赢取 《编程之美--微软技术面试心得》/BCZM.asp
分析与解法
【问题 1 的解法一】
这个问题看上去并不是一个困难的问题,因为不需要太多的
思考,我想大家都能找到一个最简单的方法来计算 f (N ),那就
是从 1 开始遍历到 N ,将其中每一个数中含有“1”的个数加起来,
自然就得到了从 1 到 N 所有“1”的个数的和。写成程序如下:
代码清单 2-9
ULONGLONG Count1InAInteger(ULONGLONG n)
{
ULONGLONG iNum = 0;
while(n != 0)
{
iNum += (n % 10 == 1) ? 1 : 0;
n /= 10;
}
return iNum;
}
ULONGLONG f(ULONGLONG n)
{
ULONGLONG iCount = 0;
for (ULONGLONG i = 1; i = n; i++)
{
iCount += Count1InAInteger(i);
}
写书评,赢取 《编程之美--微软技术面试心得》/BCZM.asp
return iCount;
}
这个方法很简单,只要学过一点编程知识的人都能想到,实
现也很简单,容易理解。但是这个算法的致命问题是效率,它的
时间复杂度是
O (N )×计算一个整数数字里面“1”的个数的复杂度 = O (N *
log2 N )
如果给定的 N 比较大,则需要很长的运算时间才能得到计算
结果。比如在笔者的机器上,如果给定 N=100 000 000 ,则算出f
(N )大概需要40 秒的时间,计算时间会随着 N 的增大而线性增
长。
看起来要计算从 1 到 N 的数字中所有 1 的和,至少也得遍历
1 到 N 之间所有的数字才能得到。那么能不能找到快一点的方法
来解决这个问题呢?要提高效率,必须摈弃这种遍历 1 到 N 所有
数字来计算f (N )的方法,而应采用另外的思路来解决这个问题。
【问题1 的解法二】
仔细分析这个问题,给定了 N ,似乎就可以通过分析“小于N
的数在每一位上可能出现 1 的次数”之和来得到这个结果。让我们
来分析一下对于一个特定的 N ,如何得到一个规律来分析在每一
位上所有出现 1 的可能性,并求和得到最后的f (N )。
先从一些简单的情况开始观察,看看能不能总结出什么规律。
写书评,赢取 《编程之美--微软技术面试心得》/BCZM.asp
先看 1 位数的情况。
如果 N = 3 ,那么从1 到 3 的所有数字:1、2、3 ,只有个位
数字上可能出现 1 ,而且只出现1 次,进一步可以发现如果 N 是
个位数,如果 N=1 ,那么f (N )都等于1 ,如果N=0 ,则f (N )
为 0。
再看 2 位数的情况。
如果 N=13 ,那么从1 到 13 的所有数字:1、2、3、4、5、6、
7、8、9、10、11、12、13 ,个位和十位的数字上都可能有1 ,我
们可以将它们分开来考虑,个位出现 1 的次数有两次:1 和 11 ,
十位出现 1 的次
文档评论(0)