第二章 斐波那契之旅第2/4段

投票推荐 加入书签 章节错误?快速报错

  杨成很快想到了解答方法,这得益于他有经常上博客论坛向大牛请教的习惯。

  在JavaScript中,对象常用作为缓存,对于斐波那契数列这样的固定序列,用全局对象来缓存是最好的方法。

  (Object{})

  至于具体的逻辑,很好写:

  假如缓存中没有这一项,那就缓存进去,如果存在,就直接取出来,无需重复计算。

  (hash table)

  JavaScript对象本质上是散列表,或者说哈希表。

  所以这对象的存取效率高的令人发指,几乎可以忽略性能方面的开销了。

  杨成在原本的解答上加了一些代码,用上了缓存的思想。

  “这个题目加深了一些难度啊”。

  杨成揉了揉太阳穴,看着那小册子再次犹如中了“浮空术”一般晃悠悠地飞向了半空中,开始了不急不慢地翻页。

  他看了看窗外,那高高的塔楼顶端,还有卫兵在守卫。

  这一切的一切都显得无比的真实。

  他试着把手伸出窗外,却被一种无形的力量阻隔在了屋内。

  一个系统音更是立刻响起:

  “任务中,无法离开指定区域!”

  他看了看四周,都是一些寻常人家的东西。

  不过,当他看到了一个小小的架在木炭上面的咖啡壶,一个精致的骨瓷咖啡杯,还有一碗研磨得细细的咖啡粉...

  杨成顿时有了一个不错的想法。

  我还需要一罐香浓的鲜牛奶...

  一盒高品质的方糖...

  一块最好的黑巧克力...

  嗯,这样就能度过一段快乐的时光。

  等杨成把这些都搞到手了,他嘴角还叼着一根冒着袅袅炊烟的“软中华”。

  他一下子恢复了精神,而且无比的振奋。

  嘿!哥现在法力无边!

  半空中,小册子的翻页速度越来越快,最后猛地一合拢,“啪嗒”一声又掉落在了桌面上。

  “这下子应该结束了吧”。

  杨成翻开小册子看了看。

  在他刚才作答的那片区域旁边,又多了一个绿色对勾。

  杨成感觉自己就像刚刚完成作业的小学生,在等着老师的批阅。

  这小册子果然没有辜负他的期待。

  稍等了片刻,一行行笔迹就再次出现在了空白的地方。

  “啪嗒”。

  香烟黯然跌落...

  杨成这次终于流露出凝重的表情,这下子不是小改,是大整改了!

  “依上题所述,若N在100000到400000之间,作何解?”

  杨成深吸一口气。

  在冷静地思考了五秒钟以后,他伸出一条长腿,把那根还未熄灭的香烟一脚踩得干瘪。

  烟雾散尽,香烟愉快地终结了它的使命,进入了废纸篓。

  “我大概需要这个...”

  他决定了,放弃递归,使用传统的线性方法,顺序遍历求解。

  这里的递归不是顺序的,斐波那契数列的递归方法是一种深度遍历求解,递归栈中函数作用域对象的开辟和回收都需要很多额外的性能开销,而顺序遍历则不存在这样的情况。

  顺序遍历共享的是同一个作用域!

  在早期的JavaScript中不支持块作用域,所以会共享同一个函数作用域或全局作用域。

  因为公式f(n)= f(n-1)+ f(n-2)的缘故,要求第n项你只需要分别保存第n-1项和第n-2项的结果。

  所以可以使用两个临时的变量来保存嘛。

  这样做,将算法的空间复杂度降到了最低,和递归庞大的保存栈相比,优势就太大了。

  使用循环顺序遍历,可以显著地提高速度。

  而不用担心,深度递归的函数因为“爆栈”的缘故导致运行失败...

  那就真是一件让人遗憾的事情呢!

  想清了思路,杨成正打算提笔就写,他却突然想到了一个令人震惊的后果。

  对于JavaScript,数字类型是有大小限制的。

  它在内部被表示为64位的浮点数,这和Java的double数字类型是一样的。

  (Number.MAX_SAFE_INTEGER)

  对于第几十万项的斐波那契数,它显然已经远远超出了范围!

  那么,自己的这个算法会不会导致数值溢出,从而丢失掉精度?

  好在他很快就想通了,关卡设计者怎么会想不到这样的问题,自己只要能写出正确的算法来就OK了。


本章未完,请点击下一段进行阅读!

章节目录