成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

斐波那契數(shù)列求和的js方案以及優(yōu)化

xinhaip / 1591人閱讀

摘要:在上做了一道斐波那契數(shù)列求和的題目,做完之后做了一些簡(jiǎn)單的優(yōu)化和用另一種方法實(shí)現(xiàn)。動(dòng)態(tài)規(guī)劃解決方案斐波那契數(shù)列求和除了可以用遞歸的方法解決,還可以用動(dòng)態(tài)規(guī)劃的方法解決。

在codewars上做了一道斐波那契數(shù)列求和的題目,做完之后做了一些簡(jiǎn)單的優(yōu)化和用另一種方法實(shí)現(xiàn)。

題目
function fibonacci(n) {
    if(n==0 || n == 1)
        return n;
    return fibonacci(n-1) + fibonacci(n-2);
}

以上函數(shù)使用遞歸的方式進(jìn)行斐波那契數(shù)列求和,但效率十分低,很多值會(huì)重復(fù)求值。題目要求使用 memoization方案進(jìn)行優(yōu)化。

My Solution

memoization方案在《JavaScript模式》和《JavaScript設(shè)計(jì)模式》都有提到。memoization是一種將函數(shù)執(zhí)行結(jié)果用變量緩存起來(lái)的方法。當(dāng)函數(shù)進(jìn)行計(jì)算之前,先看緩存對(duì)象中是否有次計(jì)算結(jié)果,如果有,就直接從緩存對(duì)象中獲取結(jié)果;如果沒(méi)有,就進(jìn)行計(jì)算,并將結(jié)果保存到緩存對(duì)象中。

let fibonacci = (function() {
  let memory = []
  return function(n) {
      if(memory[n] !== undefined) {
        return memory[n]
    }
    return memory[n] = (n === 0 || n === 1) ? n : fibonacci(n-1) + fibonacci(n-2)
  }
})()

使用閉包實(shí)現(xiàn)的memoization函數(shù)。測(cè)試通過(guò)之后,突然我有一個(gè)小疑問(wèn),如果將memory的類型由數(shù)組換成對(duì)象,它的運(yùn)算效率會(huì)有什么變化?于是,我將memory的類型換成了對(duì)象,并寫(xiě)了一個(gè)函數(shù)測(cè)試兩種數(shù)據(jù)類型的運(yùn)算效率。

function speed(n) {
    let start = performance.now()
    fibonacci(n)
    let end = performance.now()
    console.log(end - start)
}

所有測(cè)試只在Chrome控制臺(tái)測(cè)試,并且測(cè)試次數(shù)不多,結(jié)果不嚴(yán)謹(jǐn),請(qǐng)多多包涵。

memory類型為數(shù)組時(shí)(單位:毫秒):

speed(500)      // 0.8150000050663948
speed(5000)     // 3.1799999997019768
speed(7500)     // 4.234999991953373
speed(10000)    // 8.390000000596046

memory類型為對(duì)象時(shí)(單位:毫秒):

speed(500)      // 0.32499999552965164
speed(5000)     // 1.6499999985098839
speed(7500)     // 2.485000006854534
speed(10000)    // 2.9999999925494194

雖然測(cè)試過(guò)程不嚴(yán)謹(jǐn),但還是可以說(shuō)明一點(diǎn)問(wèn)題的。memory類型為對(duì)象是明顯比類型為數(shù)組時(shí),運(yùn)算速度快很多。至于為什么對(duì)象操作比數(shù)組操作的速度快,請(qǐng)?jiān)徫宜接邢?,暫時(shí)答不上來(lái)。(先挖好坑,以后回來(lái)填坑,逃)現(xiàn)在回來(lái)填坑,例如我們調(diào)用fibonacci(100),這時(shí)候,fibonacci函數(shù)在第一次計(jì)算的時(shí)候會(huì)設(shè)置memory[100]=xxx,此時(shí)數(shù)組長(zhǎng)度為101,而前面100項(xiàng)會(huì)初始化為undefined。正因?yàn)槿绱耍琺emory的類型為數(shù)組的時(shí)候比類型是對(duì)象的時(shí)候慢。(這里藥感謝hsfzxjy的提醒)

Best Solution

別人的解決方案給了我靈感,讓我想出了一個(gè)緩存效率高很多的方案。

var fibonacci = (function () {
  var memory = {}
  return function(n) {
    if(n==0 || n == 1) {
      return n
    }
    if(memory[n-2] === undefined) {
      memory[n-2] = fibonacci(n-2)
    }
    if(memory[n-1] === undefined) {
      memory[n-1] = fibonacci(n-1)
    }
    return memory[n] = memory[n-1] + memory[n-2]
  }
})()

測(cè)試結(jié)果就不放了(因?yàn)槲野l(fā)現(xiàn)在Chrome控制臺(tái)中運(yùn)行測(cè)試代碼時(shí),輸出結(jié)果不穩(wěn)定)。不過(guò),這里的緩存效率的確是提高了,前面的方案,一次計(jì)算最多緩存一個(gè)結(jié)果,而這個(gè)方案,一次計(jì)算最多緩存三個(gè)結(jié)果。從這個(gè)方面考慮,運(yùn)算速度理論上是會(huì)比前面的方案快的。

動(dòng)態(tài)規(guī)劃解決方案

斐波那契數(shù)列求和除了可以用遞歸的方法解決,還可以用動(dòng)態(tài)規(guī)劃的方法解決。由于我是算法渣,對(duì)動(dòng)態(tài)規(guī)劃了解不多,只懂一點(diǎn)點(diǎn)皮毛,所以這里就不解釋動(dòng)態(tài)規(guī)劃的概念了。(一不小心又挖了一個(gè)坑,逃)

直接貼代碼好了:

function fibonacci(n) {
    let n1 = 1,
        n2 = 1,
        sum = 1
    for(let i = 3; i <= n; i += 1) {
        sum = n1 + n2
        n1 = n2
        n2 = sum
    }
    return sum
}
尾遞歸方案

在ES6規(guī)范中,有一個(gè)尾調(diào)用優(yōu)化,可以實(shí)現(xiàn)高效的尾遞歸方案。(感謝李引證的提醒)

"use strict"
function fibonacci(n, n1, n2) {
    if(n <= 1) {
        return n2
    }
    return fibonacci(n - 1, n2, n1 + n2)
}

ES6的尾調(diào)用優(yōu)化只在嚴(yán)格模式下開(kāi)啟,正常模式是無(wú)效的。

通項(xiàng)公式方案

斐波那契數(shù)列是有通項(xiàng)公式的,但通項(xiàng)公式中有開(kāi)方運(yùn)算,在js中會(huì)存在誤差,而fib函數(shù)中的Math.round正式解決這一問(wèn)題的。(感謝公子的指導(dǎo))

function fibonacci(n){
    var sum = 0
    for(let i = 1; i <= n; i += 1) {
        sum += fib(i)
    }
    return sum

    function fib(n) {
      const SQRT_FIVE = Math.sqrt(5);
      return Math.round(1/SQRT_FIVE * (Math.pow(0.5 + SQRT_FIVE/2, n) - Math.pow(0.5 - SQRT_FIVE/2, n)));
    }
}
結(jié)語(yǔ)

只要注意細(xì)節(jié),我們的代碼還是有很大的優(yōu)化空間的。有時(shí)候,你可能會(huì)疑惑,優(yōu)化前后的性能沒(méi)有明顯的變化。我認(rèn)為,那是你的應(yīng)用規(guī)?;蛘邤?shù)據(jù)量不夠大而已,當(dāng)它們大到一定程度的時(shí)候,優(yōu)化的效果就很明顯了。優(yōu)化還是要堅(jiān)持的,萬(wàn)一哪一天我們接手大型應(yīng)用呢?

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/80652.html

相關(guān)文章

  • js 實(shí)現(xiàn)斐波那契數(shù)列(數(shù)組緩存、動(dòng)態(tài)規(guī)劃、尾調(diào)用優(yōu)化)

    摘要:根據(jù)該規(guī)則,返回第個(gè)斐波那契數(shù)。尾遞歸函數(shù)調(diào)用自身,稱為遞歸。一個(gè)前端眼中的斐波那契數(shù)列解斐波那契數(shù)列的實(shí)用解法調(diào)用棧尾遞歸和手動(dòng)優(yōu)化尾調(diào)用優(yōu)化譯我從用寫(xiě)斐波那契生成器中學(xué)到的令人驚訝的件事 斐波那契數(shù)列是以下一系列數(shù)字: 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, ... 在種子數(shù)字 0 和 1 ...

    趙連江 評(píng)論0 收藏0
  • 使用js實(shí)現(xiàn)斐波那契數(shù)列

    摘要:前言前幾天面試被問(wèn)到了斐波那契數(shù)列的實(shí)現(xiàn)以及優(yōu)化的問(wèn)題,當(dāng)時(shí)現(xiàn)場(chǎng)卡了挺久的,現(xiàn)在進(jìn)行一下總結(jié)使用實(shí)現(xiàn)。題目介紹斐波那契數(shù)列又被稱為黃金分割數(shù)列,指的是這樣的一個(gè)數(shù)列,它有如下遞推的方法定義是正整數(shù),請(qǐng)使用實(shí)現(xiàn)斐波那契函數(shù)。 前言 前幾天面試被問(wèn)到了斐波那契數(shù)列的實(shí)現(xiàn)以及優(yōu)化的問(wèn)題,當(dāng)時(shí)現(xiàn)場(chǎng)卡了挺久的,現(xiàn)在進(jìn)行一下總結(jié)(使用js實(shí)現(xiàn))。 題目介紹 ??斐波那契數(shù)列又被稱為黃金分割數(shù)列,指...

    alexnevsky 評(píng)論0 收藏0
  • 斐波那契數(shù)列看遞歸和動(dòng)態(tài)規(guī)劃

    摘要:大名鼎鼎的斐波那契數(shù)列,,,,,,,,使用數(shù)學(xué)歸納法可以看出其規(guī)律為。對(duì)于斐波那契數(shù)列的求解,有自頂向下的記憶化搜索遞歸和自下向上的迭代法,他們都使用了動(dòng)態(tài)規(guī)劃的思想。 大名鼎鼎的斐波那契數(shù)列:0,1,1,2,3,5,8,13,21...使用數(shù)學(xué)歸納法可以看出其規(guī)律為:f(n) = f(n-1) + f(n-2)。 遞歸 下面首先直接使用遞歸(JavaScript實(shí)現(xiàn))來(lái)求解第 n ...

    charles_paul 評(píng)論0 收藏0
  • 遞歸

    摘要:遞歸概念遞歸是一種針對(duì)簡(jiǎn)單循環(huán)難以編程實(shí)現(xiàn)的問(wèn)題,通過(guò)函數(shù)調(diào)用自身,提供優(yōu)雅解決方案的技術(shù)。擁有基礎(chǔ)情況或終止條件來(lái)停止遞歸。這個(gè)稱之為遞歸調(diào)用。為了避免重新創(chuàng)建字符串,使用遞歸輔助方法來(lái)進(jìn)行改良。 遞歸概念 遞歸是一種針對(duì)簡(jiǎn)單循環(huán)難以編程實(shí)現(xiàn)的問(wèn)題,通過(guò)函數(shù)調(diào)用自身,提供優(yōu)雅解決方案的技術(shù)。 遞歸都具有以下三個(gè)要點(diǎn): 使用 if-else 或 switch 語(yǔ)句來(lái)引導(dǎo)不同的情況。 ...

    alphahans 評(píng)論0 收藏0
  • 太原面經(jīng)分享:如何用js實(shí)現(xiàn)返回斐波那契數(shù)列第n個(gè)值函數(shù)

    摘要:那其實(shí)這個(gè)問(wèn)題還可以換個(gè)問(wèn)法實(shí)現(xiàn)一個(gè)函數(shù),輸入一個(gè)數(shù)字能返回斐波那契數(shù)列的第個(gè)值。文章預(yù)告更多的前端面試分享我都會(huì)第一時(shí)間更新在我的公眾號(hào)閏土大叔里面,歡迎關(guān)注 面試攢經(jīng)驗(yàn),lets go! 值此高考來(lái)臨之際,閑不住的我又雙叒叕出發(fā)去面試攢經(jīng)驗(yàn)了,去了公司交待一番流程后,面試官甩給了我一張A4紙,上面寫(xiě)著一道js算法筆試題(一開(kāi)始我并不知道這是在考察js算法),上面寫(xiě)著1、1、2、3、...

    Galence 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<