`
runfeel
  • 浏览: 943852 次
文章分类
社区版块
存档分类
最新评论

经典算法题——寻找第1500个丑数

 
阅读更多

前言:

相信很多朋友们都对“丑数”有所了解,当然肯定也有人觉得这个名字好奇怪,咦,什么样的数才算是丑数咧?实际上丑数就是只包括2,3,5这三种因子的数,另外我们一般把“1”当作第一个丑数。

知道了丑数,我们很容易发现,丑数有点像质数一样,总是没有最大的。不过丑数的寻找可比质数的寻找简单得多啦,那让我们来试一试找出从小到大排序的第1500个丑数吧。


解法一:

既然知道了这个丑数的判断方法,也就是任意给我们一个自然数,我们可以判断它究竟是不是丑数。方法当然就是把这个数 a 先不断除以2,直到有余数,恢复一步,得到 x;再把 x 不断除以3,直到有余数,恢复一步,得到 y ;最后把 y 不断除以5,如果最后余数为 1 ,就说明这个数 a 是丑数,余数不为 1 则说明 a 包含其他除了2,3,5的因子。

看一看代码:

int number = 1500; //要求输出丑数的数
int index = 1; //数字本身
while(number > 0){
int temp = index;
while(temp%2 == 0)temp = temp/2;
while(temp%3 == 0)temp = temp/3;
while(temp%5 == 0)temp = temp/5;
if(temp == 1)
{
System.out.println(index+"number="+number);
number--;
}
index++;
}


但是,但是,我们发现运行以上代码,电脑就开始不停地算了~~~~算啊算啊算啊算,差不多要几十秒才能得到我们想要的数。这是为什么呢?噢,看一下我们得到的那个第1500个丑数就明白了,859963392。。。好大。。。

也就是说,我们的计算机从1开始一直判断所有的数是不是丑数,一直判断到我们这个 8 亿多这么大的这个数。。。原来人家计算机几十秒算了这么多东西在此,我想崇敬地说一句“计算机,您辛苦了(*^__^*) ”

可是,这样计算机太可怜了,一定有什么方法帮帮她~~~~哎,对噢,判断需要判断8亿次,但是丑数只有1500个,如果我们能只做1500次操作而不是8亿次操作,效率自将大升。我们可以看看能不能直接计算出丑数,也就是说,给出现有的丑数,我们来找出下一个丑数,可以吗?当然啦~



解法二:

赶紧来试一试。不过假设给了我们从1开始的10个丑数,怎么找出第11个呐?等等,诶,丑数不是只由2,3,5构成的嘛,而且我们拿到的数也是由2,3,5构成的,而且是最小的10个,那么第11个一定就比前十个数中的某一个多一个因子2,或者因子3,或者因子5……也就是说,第11个丑数一定是前十个丑数中某一个丑数的2倍,或者3倍,或者5倍!!

这个很关键,再仔细想一想噢。现在知道了第11个丑数一定是前十个丑数中某一个丑数的2倍,或者3倍,或者5倍,还是不行呢,那到底是2倍还是3倍还是5倍呢o(︶︿︶)o。。。

想起来啦,我们的第十一个丑数一定是,大于第十个丑数的所有丑数中,最小的!!!那就是说,我们可以在第一到第十个丑数中找出某个丑数 a ,它的两倍刚好大于第十个丑数(刚好的意思就是,上一个数的两倍还小于第十个丑数,而它自己的两倍却大于第十个丑数了);然后再找出前十个丑数中的三倍刚好大于第十个丑数的家伙 b ;最后找出前十丑数中某丑数5倍刚好大于第十个丑数的丑数 c ~~~2*a,3*b,5*c,找出这三个中最小的就行啦(*^__^*)

来来来,看看代码咯:

int num[]=new int[1501];
num[0] = 0;
num[1] = 1;
int two = 0,three = 0,five = 0;//刚好大于现有最大丑数的三个
for(int i = 1; i <= 1499; i++)

{//每次找出一个丑数
for(int j = 1; j <= i ; j++)//从头向后扫描,若某数的两倍刚好大于上回找出的丑数,将它值记录下来
if((2*num[j-1] <= num[i])&&(2*num[j] > num[i])) two=num[j]*2;
for(int j = 1; j <= i ; j++)//从头向后扫描,若某数的三倍刚好大于上回找出的丑数,将它值记录下来
if((3*num[j-1] <= num[i])&&(3*num[j] > num[i])) three=num[j]*3;
for(int j = 1; j <= i ; j++)//从头向后扫描,若某数的五倍刚好大于上回找出的丑数,将它值记录下来
if((5*num[j-1] <= num[i])&&(5*num[j] > num[i])) five=num[j]*5;
//比较出三个数中最小的
if(two>=three&&five>=three) num[i+1] = three;
else if(two>=five&&three>=five) num[i+1] = five;
else if(five>=two&&three>=two) num[i+1] = two;
}
System.out.println("第1500个丑数 = "+num[1500]);


赶紧去跑一跑,有没有发现这速度比前一条快的不是一点半点哈哈,瞬间得到结果有木有



后话:

我后来继续思索这个问题,隐隐约约感觉到还有更优的方法。因为丑数不是仅由2,3,5构成嘛,所以从理论上出发,完全可以自己用2,3,5自主构建出从小到大的丑数。我感觉比如拿到一个丑数,它的2,3,5的构成个数就一定了,那应该可以推断出下一个丑数的2,3,5的构成。如果能完成这个功能,其效率肯定比解法二更优。

不过理论成立,实际不太可行,因为虽然知道某丑数2,3,5构成,下一个数的2,3,5构成确实应该是一定的,但是我们没办法通过简单的算法计算得到。

所以实现此方法的唯一方式只能通过人为映射(就是相当于打表)。而这样的映射的复杂性增加速度是很恐怖的,所以这样的方法看来确实没有实现的可能了。

当然这样的思路也提供了另一种方法,比如某丑数的2,3,5因子数分别为x,y,z ,那么下一个数的2,3,5因子数必将在0—(x+y*y+z*z*z),0—(x+y+z*z),0—(sqrt(x)+y+z)范围内,由此推断下一个。好吧,这个方法也麻烦的可以,不过我就想告诉大家,算法题的解法总是很多样化的,大家一定要亲自去探索,很可能获取一些意外收获噢(*^__^*)


分享到:
评论

相关推荐

    乘法器的演化生成vc++

    在1500代左右的平均演化代数下,意味着算法会经过大约1500次迭代来不断优化电路设计,直到找到一个相对最优的解决方案。这需要合理设置遗传算法的参数,如种群大小、交叉概率、突变概率等,以确保既能充分探索设计...

    基于Andorid的音乐播放器项目改进版本设计.zip

    基于Andorid的音乐播放器项目改进版本设计实现源码,主要针对计算机相关专业的正在做毕设的学生和需要项目实战练习的学习者,也可作为课程设计、期末大作业。

    uniapp-machine-learning-from-scratch-05.rar

    uniapp-machine-learning-from-scratch-05.rar

    game_patch_1.30.21.13250.pak

    game_patch_1.30.21.13250.pak

    【毕业设计-java】springboot-vue计算机学院校友网源码(完整前后端+mysql+说明文档+LunW).zip

    【毕业设计-java】springboot-vue计算机学院校友网源码(完整前后端+mysql+说明文档+LunW).zip

    机器学习-特征工程算法

    特征变换 特征选择

    吸烟数据集 991张原始图片,平均识别率在88.3% coco json格式标注

    吸烟数据集 991张原始图片,平均识别率在88.3% coco json格式标注

    c++万能头文件picture.h

    c++万能头文件picture.h

    spaceX Ship Flight Test 8

    spaceX 动力学分析

    数据科学_Python手册_在线学习资源_教育辅助_1741398259.zip

    python教程学习

    Uniapp 跨平台开发框架的学习资源汇总与应用指导

    内容概要:本文详细整理了与uniapp有关的一系列学习资源及开发工具。首先对官方文档与教程进行梳理,这是学习uni-app的基础部分,涵盖从基本概念到具体开发指引的全方位资料。接着详细介绍了一款专为uni-app打造的高效开发工具HBuilderX的功能特点及其使用指南,并提到了CLI命令行工具可用于完成开发过程中的常规操作任务。同时,指出uni-app所处的强大社区氛围,无论是社区还是论坛都为开发者解决了实际遇到的问题并分享了大量有价值的经验;还提及多个专门为uni-app量身定制的UI框架和丰富的组件库,进一步提高了开发的便捷性和灵活性;最后列举了几类学习资源,诸如视频教程、博客与文章还有相关书籍均能助力新手成长为熟练工。所有这些资源都将有助于深入学习和理解uni-app这个跨平台框架的相关知识点,进而开发出优秀的多平台应用程序。 适用人群:有意进入跨平台移动应用开发领域的初学者,以及希望提升开发技能的专业人士。 使用场景及目标:为想要深入了解或者开始使用uni-app框架进行开发的人群提供完整路径指导;为目标受众建立起一套完整的学习路径来降低入门难度并提升实际操作能力。

    AI Agent 行业研究报告.pdf

    AI Agent 行业研究报告.pdf

    kibana-7.10.2 docker镜像压缩包,百度网盘

    请到网盘中自取压缩包,此包为kibana-7.10.2 镜像压缩包,是通过现有镜像导出来的,主要是为了解决有些机器无法连接外网,导致无法下载镜像 加载镜像: docker load -i kibana-7.10.2.tar 查看镜像: docker images 备注:elk此镜像配套资源,相同版本的elasticsearch和logstash,请在我的资源中搜索其他镜像

    图解AUTOSAR-CP-TcpIp逻辑图打包

    图解AUTOSAR-CP-TcpIp逻辑图打包

    【毕业设计-java】springboot-vue交友网站平台实现源码(完整前后端+mysql+说明文档+LunW).zip

    【毕业设计-java】springboot-vue交友网站平台实现源码(完整前后端+mysql+说明文档+LunW).zip

    海康相机平场矫正对比图

    海康相机平场矫正对比图

    数据科学_Python基础_数据分析_学习资源.zip

    python教程学习

    基于51单片机的蓝牙家电开关控制的设计与实现

    【论文+PPT+代码+开题+任务书】手机APP遥控的相关测试主要完成设计当中按键控制对应继电器是否正确打开以及关上,可以通过观察按下按键时继电器想匹配的LED是否点亮来进行验证。 进入手机APP后,根据APP中的按键分别控制不同的继电器,继电器1这个按键控制对应1号继电器的开启和关闭,手机蓝牙按下按键由OFF转变为ON那么电控制器件就可以变化一次,1号指示灯就可以由暗变亮了,再次按下手机蓝牙按键由ON转变为OFF电控制器件又变化一次,1号指示灯就可以由亮变暗。 如果点击继电器2则控制对应2号继电器的开启和关闭,手机蓝牙按下按键由OFF转变为ON那么电控制器件就可以变化一次,2号指示灯就可以由暗变亮了,再次按下手机蓝牙按键由ON转变为OFF电控制器件又变化一次,2号指示灯就可以由亮变暗。 如果点击继电器3则控制对应3号继电器的开启和关闭,手机蓝牙按下按键由OFF转变为ON那么电控制器件就可以变化一次,3号指示灯就可以由暗变亮了,再次按下手机蓝牙按键由ON转变为OFF电控制器件又变化一次,3号指示灯就可以由亮变暗。 如果点击继电器4则控制对应4号继电器的开启和关闭

    【毕业设计】java-springboot+vue教师人事档案管理系统实现源码(完整前后端+mysql+说明文档+LunW).zip

    【毕业设计】java-springboot+vue教师人事档案管理系统实现源码(完整前后端+mysql+说明文档+LunW).zip

    ChatGPT付费创作系统V3.1.5独立版 WEB端+H5端+小程序端(优化DeepSeek接口)

    ChatGPT付费创作系统V3.1.5独立版 WEB端+H5端+小程序端 (优化DeepSeek推理模型新增 阿里百炼、腾讯云、硅基流动接口) 是基于国外很火的ChatGPT进行开发的Ai智能多端系统。相比传统的问答系统, ChatGPT可以更加准确地理解用户的意图,提供更加精准的答案。同时系统采用了最新的GPT3.5接口与GPT4模型, 同时还支持DeepSeek,LocalAI、Claude3、豆包AI、文心一言,腾讯混元,讯飞星火,通义千问, 智普等等国内外各种大模型接口,视频音乐支持Pika、Runway、SunoAI接口,可以更好地适应不同的应用场景, 支持站点无限多开,支持WEB端、H5端、小程序端, 可以说ChatGPT付费创作系统目前国内相对体验比较好的一款的ChatGPT及多接口AI软件系统。 新增DeepSeek高级通道新增 阿里百炼、腾讯云、硅基流动3个接口、取消 国内AI通道 的敏感词过滤, 修复”高级版DeepSeek“计费bug,修复DeepSeek的上下文关联,支持AI接口输出的reasoning_content字段

Global site tag (gtag.js) - Google Analytics