JavaScript程序設(shè)計高級算法之動態(tài)規(guī)劃實(shí)例分析
本文實(shí)例講述了JavaScript程序設(shè)計高級算法之動態(tài)規(guī)劃。分享給大家供大家參考,具體如下:
主要是看了《數(shù)據(jù)結(jié)構(gòu)與算法》有所感悟,雖然這本書被挺多人詬病的,說這有漏洞那有漏洞,但并不妨礙我們從中學(xué)習(xí)知識。
其實(shí)像在我們前端的開發(fā)中,用到的高級算法并不多,大部分情況if語句,for語句,swith語句等等,就可以解決了。稍微復(fù)雜的,可能會想到用遞歸去的解決。
但要注意的是遞歸寫起來簡潔,但實(shí)際上執(zhí)行的效率并不高。
我們再看看動態(tài)規(guī)劃的算法:
動態(tài)規(guī)劃解決方案從底部開始解決問題, 將所有小問題解決掉, 然后合并成一個整體解決方案, 從而解決掉整個大問題 。
實(shí)例舉例 (計算斐波那契數(shù)列)
斐波那契數(shù)列指的是這樣一個數(shù)列 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368........
這個數(shù)列從第3項(xiàng)開始,每一項(xiàng)都等于前兩項(xiàng)之和。
針對這個數(shù)列,可以用一個遞歸的函數(shù)去計算第n項(xiàng) 數(shù)值
// 斐波那契數(shù)列 function recurFib(n) { if(n < 2){ return n ; }else { // document.write("第"+(n-1)+"次計算 n-1="+(n-1)+recurFib(n-1)+' '); // document.write("n-2="+(n-2)+recurFib(n-2)+"<br>"); return recurFib(n-1)+recurFib(n-2) } }
確實(shí)是個非常簡潔的代碼,上面有被注釋的代碼 ,是用來打印出當(dāng)n=多少,要執(zhí)行多少次函數(shù),不過明眼人一眼就能看出來執(zhí)行的次數(shù)隨著n的變大,次數(shù)也會非常恐怖增長。
當(dāng)n=5的時候,遞歸樹已經(jīng)長的很大了……可以預(yù)見當(dāng)n=10,甚至n=100的時候……
明白了遞歸函數(shù)執(zhí)行效率之差,我們再來看的動態(tài)規(guī)劃是如何做的
function dynFib(n) { let val = []; for(let i = 0; i <= n; ++i){ val[i]=0; } if(n ===1 || n === 2){ return 1; } else { val[1] =1; val[2] = 2; for(let i = 3; i <= n; ++i){ val[i] = val [i-1] +val[i-2] ; } } return val[n-1] }
通過數(shù)組 val 中保存了中間結(jié)果, 如果要計算的斐波那契數(shù)是 1 或者 2, 那么 if 語句會返回 1。 否則,數(shù)值 1 和 2 將被保存在 val 數(shù)組中 1 和 2 的位置。
循環(huán)將會從 3 到輸入的參數(shù)之間進(jìn)行遍歷, 將數(shù)組的每個元素賦值為前兩個元素之和, 循環(huán)結(jié)束, 數(shù)組的最后一個元素值即為最終計算得到的斐波那契數(shù)值, 這個數(shù)值也將作為函數(shù)的返回值。
接下來可以寫個簡單的測試函數(shù),來對比兩者的運(yùn)行時間。
// 定義一個測試函數(shù),將待測函數(shù)作為參數(shù)傳入 function test(func,n){ let start = new Date().getTime();//起始時間 let res = func(n);//執(zhí)行待測函數(shù) document.write('<br>'+'當(dāng)n='+n+'的時候 '+res+'<br>'); let end = new Date().getTime();//結(jié)束時間 return (end - start)+"ms";//返回函數(shù)執(zhí)行需要時間 }
打印函數(shù)執(zhí)行
let time = test(recurFib,40); document.write(time); let time2 = test(dynFib,40); document.write(time2);
結(jié)果如下:
最后, 你或許已經(jīng)意識到在使用迭代的方案計算斐波那契數(shù)列時, 是可以不使用數(shù)組的。
需要用到數(shù)組的原因是因?yàn)閯討B(tài)規(guī)劃算法通常需要將中間結(jié)果保存起來。
以下是迭代版本的斐波那契函數(shù)義
function iterFib(n) { let last = 1; let nextLast = 1; let result = 1; for (let i = 2; i < n; ++i) { result = last + nextLast; nextLast = last; last = result; } return result; }
當(dāng)然這個迭代版本的與數(shù)組的版本的效率也是相同的。
更多關(guān)于JavaScript相關(guān)內(nèi)容感興趣的讀者可查看本站專題:《JavaScript數(shù)據(jù)結(jié)構(gòu)與算法技巧總結(jié)》、《JavaScript數(shù)學(xué)運(yùn)算用法總結(jié)》、《JavaScript排序算法總結(jié)》、《JavaScript遍歷算法與技巧總結(jié)》、《JavaScript查找算法技巧總結(jié)》及《JavaScript錯誤與調(diào)試技巧總結(jié)》
希望本文所述對大家JavaScript程序設(shè)計有所幫助。
相關(guān)文章
js判斷手機(jī)號是否正確并返回的實(shí)現(xiàn)代碼
這篇文章主要介紹了js判斷手機(jī)號是否正確并返回的實(shí)現(xiàn)代碼,以及使用正則表達(dá)式判斷手機(jī)號是否正確,需要的的朋友參考下2017-01-01微信小程序教程系列之設(shè)置標(biāo)題欄和導(dǎo)航欄(7)
這篇文章主要為大家詳細(xì)介紹了微信小程序教程系列之標(biāo)題欄和導(dǎo)航欄的設(shè)置,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-04-04Electron 打包問題:electron-builder 下載各種依賴出錯(推薦)
這篇文章主要介紹了Electron 打包問題:electron-builder 下載各種依賴出錯,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-07-07Javascript中的for in循環(huán)和hasOwnProperty結(jié)合使用
當(dāng)檢測某個對象是否擁有某個屬性時,hasOwnProperty 是唯一可以完成這一任務(wù)的方法,在 for in 循環(huán)時,建議增加 hasOwnProperty 進(jìn)行判斷,可以有效避免擴(kuò)展本地原型而引起的錯誤2013-06-06axios請求設(shè)置responseType為'blob'或'arraybuffer&apo
這篇文章主要給大家介紹了關(guān)于axios請求設(shè)置responseType為'blob'或'arraybuffer'下載時如何正確處理返回值的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01獲取下拉列表框的值是數(shù)組,split,$.inArray示例
獲取下拉列表框的值是數(shù)組,下面用product_id 去匹配是否包含在一個數(shù)組中,感興趣的朋友不要錯過2013-11-11一文詳解JavaScript中的事件循環(huán)(event?loop)機(jī)制
JavaScript中的事件循環(huán)(Event?Loop)是一種重要的機(jī)制,用于管理異步代碼的執(zhí)行,它確保?JavaScript?單線程環(huán)境中的任務(wù)按照正確的順序執(zhí)行,同時允許異步操作如定時器、網(wǎng)絡(luò)請求和事件處理,本將給大家詳細(xì)的介紹一下JavaScript事件循環(huán)機(jī)制,感興趣的朋友可以參考下2023-12-12