在csdn上面看到一道题目:
对于任意正整数n,f(n)表示从1到n中数字1出现的次数。例如f(3)=1; f(11)=4; f(13)=6;
设计一个算法来计算f(n);
最开始想到的算法是最直接的算法:对1到n的每个数字m,将m转换成字符串,计算该字符串中字符‘1’出现的次数。所有的次数的和就是计算的结果。具体算法如下:
public long countAppearTimes(long n)
{
long appearTimes = 0;
for (long i = 1; i <= n; i++)
{
String strN = String.valueOf(i);
int length = strN.length();
for (int i=0; i< length; i++)
{
if (strN.charAt(i) == ‘1’)
{
appearTimes = appearTimes + 1;
}
}
}
return appearTimes;
}
这个算法比较直接,也比较好理解,但是效率太低下。当n比较小的时候还显示不出来,但是当n比较大的时候,就十分明显了。在我的机器上,当n=999999999时,运行了540047ms,也就是9分钟的时间。
是否有比较简单、高效的算法呢?
我们来做一下转换。假设给出的n是一个m位的数字,可以表示为
a1a2a3a4a5a6......am。那么将从1到n的所有的数字都按m位编写,不足的在左端补0。具体形式如下
0 0 0 0 ...... 0 0 1
0 0 0 0 ...... 0 0 2
......
0 0 0 0 ...... 0 1 0
0 0 0 0 ...... 0 1 1
......
a1 a2 a3 a4 。。。。。。 am-2 am-1 am
我们可以发现以下的规律:
个位上的数字,每10个中就有1个1;
十位上的数字,每100个中有10个1;(10——19)
百位上的数字,每1000个中有100个1;(100——199)
依次类推,在从前向后数的第i位上的数字,每10m-i+1个中就有10m-i个1。
因此,对于n= a1a2a3a4a5a6......am;第i位的数字为ai
1. 如果ai 等于0,那么第i位上有 a1a2a3a4a5a6...... ai-1 * 10 m-i 个1。
也就是说,如果ai 等于0,那么第i位上的1的个数为n/10m-i+1*10m-i个1;
注意,/表示整除,例如132/10 = 13。以下相同。
例如:n=13059;第三位为0。那么第三位上的1共有
13059/105-3+1*105-3=1300个。即
100——199,1100——1199,2100——2199,3100——3199,4100——4199,5100——5199,6100——6199,7100——7199,8100——8199,......,13100——13199。
2. 如果ai等于1,那么从1到a1a2a3a4a5a6... ai-1099...9,第i位上的1的个数可以根据情况1计算出来。从a1a2a3a4a5a6... ai-1100...0到a1a2a3a4a5a6... ai-11 ai+1 ai+2... am 中第i位上的1的个数为 ai+1 ai+2... am+1个,即n%10m-i + 1个。(%表示取余,例如132 %10 = 2。以下相同)所以第i位上共有n/10m-i+1*10m-i + n%10m-i + 1个1。
3. 如果ai位是其他的数字,那么第i位上共有n/10m-i+1*10m-i + 10m-i =(n/10m-i+1+1)* 10m-i个1。具体的推算各位可以自己去验证。
根据这思想,就有以下的算法。
public long countAppearTimes(long n){
long times = 0;
String str = String.valueOf(n);
int length = str.length();
for (int i=0; i<length; i++){
//注意这里i是从0开始的,上面的算法描述中的是从1开始的,因此以下的程序稍有不同。
long exp = Math.round(Math.pow(10, length-i-1));
long mod = n % exp;
long div = n / exp;
long tempTimes = 0;
if (str.charAt(i)=='1'){
tempTimes = mod + 1;
tempTimes = tempTimes + (div -1) * exp / 10;
times = times + tempTimes;
}
else{
if (str.charAt(i) == '0')
tempTimes = tempTimes + div / 10 * exp;
else
tempTimes = tempTimes + (div /10 +1)*exp;
times = times + tempTimes;
}
}
return times;
}
通过验证,这个算法和最原始的算法的结果是完全相同的(验证了从1到99999999)。
这个算法的效率如何呢?当n=999999999时,运行了109ms。
分享到:
相关推荐
在上面的代码中,我们可以看到几个控制语句的应用: 1. if语句:用于判断某个条件是否成立,如果成立则执行某些语句。例如,在第一个程序中,我们使用if语句来判断是否是“水仙花数”。 2. for循环语句:用于重复...
今天刚刚通过OCJP考试,感觉题目比较简单,资料里面的题目做完基本上就可以应付了,我把从CSDN还有其他上面搜到的题目全部都放到一起了。里面有一个模拟器,和真实环境里面的差不多,还有就是公认的那本考试指南,...
下面关于“联合”的题目的输出? a) #i nclude <stdio.h><br>union { int i; char x[2]; }a; <br>void main() { a.x[0] = 10; a.x[1] = 1; printf("%d",a.i); } 答案:...
Scratch青蛙过河 第十五届蓝桥杯scratch图形化编程源程序 少儿编程创意编程选拔赛真题源...期待小朋友们相互交流学习,有什么问题,建议或者意见可以直接给博主留言,或者私下,博主看到后会第一时间给到您相应的回复
在读取每一项时,根据上面提到的三个关键点进行条件判断,决定如何输出系数和指数。同时,`t`变量用来记录是否是第一个输出的项,以便决定是否需要在项前添加加号"+"。 总的来说,此题目的解题核心在于理解和运用...
它是一种在线的编程练习平台,用户可以在上面提交代码,系统会自动运行并判断代码是否符合题目要求,给出正确或错误的反馈。武汉大学的WOJ(Whu Online Judge)就是这样的一个平台,为学生提供了丰富的编程题目,...
PUDN(Programmers' University Data Network)是一个知名的中文技术分享平台,用户可以在上面找到各种编程学习资料和解决方案,包括ACM竞赛相关的题目和解析。 总的来说,这个压缩包为想要了解或准备参与ACM竞赛的...
CSDN是一个程序员交流平台,上面有许多编程相关的资源分享,包括但不限于比赛题目、教程、源代码等。这意味着这些试题可能由CSDN的用户上传分享,供其他人学习和参考。 综上所述,2008年百度之星程序设计比赛的试题...
根据题目中的描述和部分代码示例,我们将详细介绍几个常用的Maven命令: ##### 1. 上传POM文件 命令格式如下: ```shell mvn deploy:deploy-file -DgroupId=...
测绘程序设计是大题目,在测绘工作与科学研究中,很多情况下都可以使用计算机。测绘工程所涉及的数据计算、绘图、数据库管理、数据分析等,都可以使用计算机来完成。从一般含义上说,测绘工作包含计算和绘图两个方面...
这段描述告诉我们,这份解答是针对 CSDN 编程大赛中的一项挑战题目的解决方案,并且已经经过验证能够正确运行。这意味着我们可以信任这份解答的有效性和准确性。 ### 题目解析 题目要求确定一个坐标 `(x, y)` 对应...
题目中给出了部分伪代码示例,这里不再赘述,但可以根据上面的算法描述完成具体的代码实现。 #### 九、结论 次小生成树问题虽然比最小生成树问题更为复杂,但在实际应用中有着广泛的需求,例如在网络设计、通信...
含程序 题目 【问题描述】 相传在一个古老的阿拉伯国家里,有一座宫殿。宫殿里有个四四方方的格子迷宫,国王选择驸马的方法非常特殊,也非常简单:公主就站在其中一个方格子上,只要谁能用地毯将除公主站立的地方外...
- **设计思路:** 类似于上面的设计,但只需要区分是否至少有两个`a`即可。 - **转换规则:** - 从q0到q1:读取`a`时进入。 - 从q1到q2:再次读取`a`时进入,q2为接受状态。 - 从q2到q2:无论读取什么字符都...
虽然题目中没有给出具体的部署步骤,但从上面的架构解析中我们可以推断出以下部署步骤: 1. **准备环境:** - 安装必要的软件包。 - 配置网络环境,确保各节点之间通信正常。 2. **部署跟踪服务器(Tracker):*...
2. **知乎**:知乎是一个知识分享社区,上面有关于“2022 数模美赛(附 O 奖论文 Word 模板)”的详细解答。这样的帖子通常会提供详细的备赛策略,包括如何选择题目、团队分工、时间管理,以及如何撰写高质量的论文...
所以我们决定,应该好好的将自己做题的思路记录下来,一个知识点,自己能弄懂,写出来让大家都明白,同时能做到举一反三,触类旁通,那么在一定程度上面才算是真的掌握了。 于是就有了现在准备开始的这本书:...