js遞歸-記憶函數-動態規劃

遞歸在處理某些問題,尤其在循環遍歷方面,常常可以用比較簡潔的代碼實現一些複雜的功能;但是由於它是調用自身,所以如果層級比較多,一是性能會比較差,其次容易出現棧溢出;

    對於這兩點通過添加一個變量存儲中間結果可以部分提升性能,但是還是有上限,尤其是調用萬級的次數,還是有棧溢出的風險;一個例子:關於斐波那契數列的值的獲取;

1 普通遞歸:

var count=0;
//斐波那契數列
var recurFib=function(n){
	count++;
	if(n<2){
		return n;
	}else{
		return recurFib(n-1)+recurFib(n-2);
	}
}

當n爲10的時候,大概需要執行177次,其中100多次的調用是重複的;當n爲1000的時候,基本上就沒法用了。

2 遞歸+記憶數組;

var countMe=0;
var recurfibMem=function(){
	var memo=[0,1];//保存中間值
	var fib=function(n){
		countMe++;
		var result=memo[n];
		if(typeof result !='number'){
			result=fib(n-1)+fib(n-2);
			memo[n]=result;
		}
		return result;
	}
	return fib;
}()

當n爲10的時候,大概需要執行19次,相比較原始的方法,少調用了很多次。當n=10000的時候,耗時在幾毫秒之間,也還不錯。但是當n的值在往上加,就可能會出現棧溢出的情形;

3 動態規劃:動態規劃從思路上講和添加記憶數組差不多。區別在於數組的值不是通過遞歸獲取的,而是通過一步步的“平行”計算獲取的,這樣就不會出現調用過深的情況;

//動態規劃
var countD=0;
var recurFibDyn=function(n){
	var last=1;
	var nextLast=1;
	var result=1;
	for(var i=2;i<n;i++){
		countD++;
		countD++;
		result=last+nextLast;
		nextLast=last;
		last=result;
	}
	return result;
}

測試結果:當n=10000的時候,耗時在2-3毫秒。當n=10w,n=100w,依然可以正常運行且時間沒有指數級別的增加。當然在這裏的話返回的值已經超出了js默認數字的最大值。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章