经典算法题 ----关于效率

问题描述

在网上看了几个算法题居然发现速度最快的接法我居然看不懂。。。。。。。。请高手帮我贴上上详细注释,或则为什么能这样算的原因把谢谢分少。。。。packagecalculation.fuxi.interstingsuanfa;/**给定一个十进制数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到N之间出现"1"的个数,比如f(12)=5一开始看这个就想到遍历1-N,每个数里面的1数量加起来,这样算法复杂度为N乘N的位数,即O(NLogN)。后来看了原作所写,这个问题有复杂度为o(LogN)的解,于是思考了一番,用递归实现了。同时写上O(NLogN)的遍历算法和原文作者的算法以作比较*/interfaceAlgrithm{publicintresolve(intnumber);}classRecursiveAlgrithmimplementsAlgrithm{//按位递归算法,o(LogN)@Overridepublicintresolve(intnumber){if(number==0){return0;}intlength=(int)Math.log10(number);if(length==0){return1;}else{intcurrentLvl=scale(10,length);inthead=number/currentLvl;if(head>1){returncurrentLvl+(head)*resolve(currentLvl-1)+resolve(number-head*currentLvl);}else{returnnumber-currentLvl+1+(head)*resolve(currentLvl-1)+resolve(number-currentLvl);}}}publicintscale(inta,intb){//指数运算intres=1;for(inti=0;i<b;i++){res=a*res;}returnres;}}classEnumerateAlgrithmimplementsAlgrithm{//遍历算法,o(NLogN)@Overridepublicintresolve(intnumber){intsum=0;for(inti=0;i<=number;i++){sum+=findInSingleNum(i);}returnsum;}privateintfindInSingleNum(intnumber){//单个数中包含'1'数量intres=0;while(number>0){if(number%10==1){res++;}number=number/10;}returnres;}}classReferedAlgrithmimplementsAlgrithm{//原作者的算法,o(LogN)@Overridepublicintresolve(intn){intcount=0;intfactor=1;intlower;intcurrent;inthigher;while(n/factor!=0){lower=n-(n/factor)*factor;current=(n/factor)%10;higher=n/(factor*10);switch(current){case0:count+=higher*factor;break;case1:count+=higher*factor+lower+1;break;default:count+=(higher+1)*factor;}factor*=10;}returncount;}}publicclassgetOne{publicstaticvoidcalculateWith(Algrithmal){longstart=System.nanoTime();intres=al.resolve(100000000);longend=System.nanoTime();System.out.println(al.getClass().getName()+":"+res);System.out.println("timecost:"+(end-start)+"ns");}publicstaticvoidmain(String[]arg){ReferedAlgrithmtest=newReferedAlgrithm();test.resolve(521);getOne.calculateWith(newRecursiveAlgrithm());getOne.calculateWith(newReferedAlgrithm());getOne.calculateWith(newEnumerateAlgrithm());}}

由于ReferedAlgrithm和RecursiveAlgrithm的算法太快,以至于以毫秒计时都是0ms,因此改用纳秒output:puzzles.RecursiveAlgrithm:80000001timecost:96940nspuzzles.ReferedAlgrithm:80000001timecost:4191nspuzzles.EnumerateAlgrithm:80000001timecost:25053647670ns可以看到原作者的算法是最快的,递归算法虽然算法复杂度同为o(LogN),不过递归在性能上不如循环,因此也差了一个数量级而最后o(NLogN)复杂度的算法,性能则整整差了6个数量级以上...这个差距,大概抵得上20年的硬件性能的发展了吧.各位有兴趣也可以用C#分别实现下这几种算法,看看和java耗时相比如何^^

解决方案

解决方案二:
这个题是微软技术面试心得上面的题,原作者的算法是分析n就可以得到f(n)而不用遍历,所以复杂度是O(len)len是n的长度而不是O(logn)
解决方案三:
使用递归相对起来好些吧!

时间: 2024-07-30 14:27:45

经典算法题 ----关于效率的相关文章

经典算法题每日演练——第二十二题 奇偶排序

原文:经典算法题每日演练--第二十二题 奇偶排序   这个专题因为各种原因好久没有继续下去了,MM吧...你懂的,嘿嘿,不过还得继续写下去,好长时间不写,有些东西有点生疏了, 这篇就从简单一点的一个"奇偶排序"说起吧,不过这个排序还是蛮有意思的,严格来说复杂度是O(N2),不过在多核的情况下,可以做到 N2 /(m/2)的效率,这里的m就是待排序的个数,当m=100,复杂度为N2 /50,还行把,比冒泡要好点,因为重点是解决问题的奇思妙想.     下面我们看看这个算法是怎么描述的,既

经典算法题每日演练——第七题 KMP算法

原文:经典算法题每日演练--第七题 KMP算法       在大学的时候,应该在数据结构里面都看过kmp算法吧,不知道有多少老师对该算法是一笔带过的,至少我们以前是的, 确实kmp算法还是有点饶人的,如果说红黑树是变态级的,那么kmp算法比红黑树还要变态,很抱歉,每次打kmp的时候,输 入法总是提示"看毛片"三个字,嘿嘿,就叫"看毛片算法"吧. 一:BF算法      如果让你写字符串的模式匹配,你可能会很快的写出朴素的bf算法,至少问题是解决了,我想大家很清楚的知

经典算法题每日演练——第十七题 Dijkstra算法

原文:经典算法题每日演练--第十七题 Dijkstra算法         或许在生活中,经常会碰到针对某一个问题,在众多的限制条件下,如何去寻找一个最优解?可能大家想到了很多诸如"线性规划","动态规划" 这些经典策略,当然有的问题我们可以用贪心来寻求整体最优解,在图论中一个典型的贪心法求最优解的例子就莫过于"最短路径"的问题.   一:概序    从下图中我要寻找V0到V3的最短路径,你会发现通往他们的两点路径有很多:V0->V4-&g

经典算法题每日演练——第十五题 并查集

原文:经典算法题每日演练--第十五题 并查集     这一篇我们看看经典又神奇的并查集,顾名思义就是并起来查,可用于处理一些不相交集合的秒杀. 一:场景     有时候我们会遇到这样的场景,比如:M={1,4,6,8},N={2,4,5,7},我的需求就是判断{1,2}是否属于同一个集合,当然实现方法 有很多,一般情况下,普通青年会做出O(MN)的复杂度,那么有没有更轻量级的复杂度呢?嘿嘿,并查集就是用来解决这个问题的.   二:操作   从名字可以出来,并查集其实只有两种操作,并(Union)

经典算法题每日演练——第二十三题 鸡尾酒排序

原文:经典算法题每日演练--第二十三题 鸡尾酒排序     这篇我们继续扯淡一下鸡尾酒排序,为了知道为啥取名为鸡尾酒,特意看了下百科,见框框的话,也只能勉强这么说了.   要是文艺点的话,可以说是搅拌排序,通俗易懂点的话,就叫"双向冒泡排序",我想作为码农的话,不可能不知道冒泡排序, 冒泡是一个单向的从小到大或者从大到小的交换排序,而鸡尾酒排序是双向的,从一端进行从小到大排序,从另一端进行从大 到小排序. 从图中可以看到,第一次正向比较,我们找到了最大值9.             

经典算法题每日演练——第三题 猴子吃桃

原文:经典算法题每日演练--第三题 猴子吃桃           猴子第一天摘下若干个桃子,当即吃了一半,还不过瘾就多吃了一个.第二天早上又将剩下的桃子吃了一半,还是不过瘾又多 吃了一个.以后每天都吃前一天剩下的一半再加一个.到第10天刚好剩一个.问猴子第一天摘了多少个桃子?   分析: 这是一套非常经典的算法题,这个题目体现了算法思想中的递推思想,递归有两种形式,顺推和逆推,针对递推,只要         我们找到递推公式,问题就迎刃而解了.                令S10=1,容易看

经典算法题每日演练——第六题 协同推荐SlopeOne 算法

原文:经典算法题每日演练--第六题 协同推荐SlopeOne 算法               相信大家对如下的Category都很熟悉,很多网站都有类似如下的功能,"商品推荐","猜你喜欢",在实体店中我们有导购来为我们服务,在网络上 我们需要同样的一种替代物,如果简简单单的在数据库里面去捞,去比较,几乎是完成不了的,这时我们就需要一种协同推荐算法,来高效的推荐浏览者喜 欢的商品. 一:概念      SlopeOne的思想很简单,就是用均值化的思想来掩盖个体的打

经典算法题每日演练——第八题 AC自动机

原文:经典算法题每日演练--第八题 AC自动机        上一篇我们说了单模式匹配算法KMP,现在我们有需求了,我要检查一篇文章中是否有某些敏感词,这其实就是多模式匹配的问题. 当然你也可以用KMP算法求出,那么它的时间复杂度为O(c*(m+n)),c:为模式串的个数.m:为模式串的长度,n:为正文的长度,那 么这个复杂度就不再是线性了,我们学算法就是希望能把要解决的问题优化到极致,这不,AC自动机就派上用场了.    其实AC自动机就是Trie树的一个活用,活用点就是灌输了kmp的思想,从

经典算法题每日演练——第十题 树状数组

原文:经典算法题每日演练--第十题 树状数组         有一种数据结构是神奇的,神秘的,它展现了位运算与数组结合的神奇魅力,太牛逼的,它就是树状数组,这种数据结构不是神人是发现不了的. 一:概序      假如我现在有个需求,就是要频繁的求数组的前n项和,并且存在着数组中某些数字的频繁修改,那么我们该如何实现这样的需求?当然大家可以往 真实项目上靠一靠. ① 传统方法:根据索引修改为O(1),但是求前n项和为O(n). ②空间换时间方法:我开一个数组sum[],sum[i]=a[1]+..