目錄
問題一了解遞迴和迭代
了解尾遞迴
如何將普通遞迴優化為尾遞迴?
有關遞迴和尾遞迴優化的文章可以參考
其它尾遞迴優化參考
問題二尾遞迴的練習:
現有n階台階,有乙隻青蛙要從台階底跳上台階頂。這只青蛙每次可以跳一階,也可以跳兩階。問這只青蛙有多少種跳法可以完成目標?
分析:這種問題可以先從簡單情況著手,記總共有jump(n)種方法。
當n=1時,jump(1) = 1; // 1
當n=2時,jump(2) = 2; // 1+1、2
當n=3時,jump(3) = 3; //1+1+1、 1+2先跳一步,再跳兩步(jump(2))、2+1先跳兩步,在跳一步
當n=4時,jump(4) = 5; //參考n=3思考過程
此時,我們發現規律為:
jump(1) = 1; jump(2) = 2;
jump(n) = jump(n-1) +jump(n-2) n >2;
//形式上為斐波那契數列
function jump(n)
if (n ==1 || n ==2) else
}console.time('jump');
console.log(jump(5)); //8 jump: 2.552978515625ms
console.log(jump(40)); //165580141 jump: 927.423095703125ms
console.endtime('jump');
仔細看一眼返回值,發現函式使用了遞迴,當呼叫過深時,耗時非常長,而且可能會造成爆棧;下面談談遞迴和迭代。
迭代:我們經常在for迴圈中寫這樣的語句: res += num; 表示將當前res值與num求和,再賦值給res,這種就i是迭代。遞迴:參考我們上面的**,遞迴可以理解為一種思想,將乙個複雜的問題分解為簡單一點的問題,此問題與原問題解法相似,直到回退為乙個基本的情景作為遞迴的出口;
遞迴的優點:1)**簡潔 2)思想清晰,易於理解
遞迴的缺點:函式呼叫是通過乙個工作棧來實現的,遞迴操作需要反覆呼叫函式自身,在這個過程中需要儲存函式執行產生的區域性變數,直到遇到基本情況時(遞迴出口),儲存的區域性變數才會被釋放。也就是說,隨著遞迴層級的逐漸深入,系統需要更多的空間去儲存上一級產生的區域性變數,這產生了巨大的效能問題。
尾遞迴顧名思義就是函式的返回值返回遞迴函式本身。遞迴由於效率低的問題,經常要求轉換成迴圈結構的非遞迴形式。那這個迴圈結構跟我們要使用尾遞迴有什麼關聯?
不是尾遞迴本身可以優化**效能,而是尾遞迴可以通過一些編譯器轉化為迴圈結構,而迴圈結構的**相對遞迴形式效率有所提高。
//斐波那契數列的尾遞迴優化
//簡單分析,將遞迴轉化為迴圈/迭代結構,那就需要乙個與迴圈結構相似的特徵:迴圈次數,這裡我們記為i
//規定了迴圈次數之後,可以有兩種策略進行計數
//公升序 i =1 -> n
function upperjump(n, i=1, pre=1, cur=1)
if (n==1 || n==2)
if (i == n)else
} console.time('upperjump');
console.log(upperjump(5));//8 tailjump: 0.27978515625ms
console.timeend('upperjump');
//降序 i=n -> 1
function downjump(n, i, pre=1, cur=1)else
} console.time('downjump');
console.log(downjump(5,5));//8 downjump: 2.082275390625ms
console.timeend('downjump');
漫談遞迴轉非遞迴
劍指offer面試題9-青蛙跳台階及其變種問題
青蛙產生了變異,不但可以一次跳一階,也可以一次跳兩階。。。也可以一次跳n階。同問對於n階台階,這個青蛙有多少中跳法?
分析
當n=1時,jump(1) = 1; // 1
當n=2時,jump(2) = 2; // 1+1、2
當n=3時,jump(3) = 4; //1+1+1、 1+2先跳一步,再跳兩步(jump(2))、2+1先跳兩步,在跳一步 、3一次跳三步
當n=4時,jump(4) = 8; //1+(ju***)、 2+ (jump(2))、3+(jump(1))
。。。當n = n時,jump (n)= jump(n-1) +jump(n-2) +...+jump(1);
對於上面的表示式,可簡化為 jump(n) = 2* jump(n-1),邊界條件 n=1時,jump(1) = 1;
function btjump(n)else
return res;
} console.time('btjump');
console.log(btjump(5));//16 btjump: 3.189208984375ms
console.timeend('btjump');
此時我們發現了,這依然時遞迴(注意與尾遞迴區別)。
//同上,我們用i計數,直到i=n時,返回結果res
//下面**為計數公升序
function upperbtjump(n, i=1, res=1)
if (i ==n) else
} console.time('upperbtjump');
console.log(upperbtjump(5));//16 upperbtjump: 0.152099609375ms
console.timeend('upperbtjump');
階乘n! 遞迴求解青蛙跳台階問題
1.乙隻青蛙一次可以跳上1級台階,也可以跳上2級台階,問這個青蛙跳上n級台階一共有多少種跳法 思路一 和漢諾塔一樣,遞迴的思路就是把問題簡化到更小規模的問題,在寫程式的時候確定兩個目標。一是如何分解乙個問題,二是當該問題分解到最簡時如何處理,將這兩塊內容通過程式告訴電腦,就可以把任務推給電腦,由電腦...
青蛙跳台階問題
題目 乙隻青蛙一次可以跳上 1 級台階,也可以跳上2 級。求該青蛙跳上乙個n 級的台階總共有多少種跳法。我的思路 最開始我的思路是把這個看成是乙個數學問題,n i 1 k 2先把所有可能滿足這個公式的i和k求出來。然後在對i和k做排列組合。很明顯i的範圍應該是0 public int jumpflo...
青蛙跳台階問題
1 乙隻青蛙一次可以跳上 1 級台階,也可以跳上2 級。求該青蛙跳上乙個n 級的台階總共有多少種跳法。2 乙隻青蛙一次可以跳上1級台階,也可以跳上2 級 它也可以跳上n 級,此時該青蛙跳上乙個n級的台階總共有多少種跳法?分析 1 當n 1,只有1中跳法 當n 2時,有兩種跳法 當n 3 時,有3種跳...