淺談遞迴
在做leetcode的時候,遇到了二叉樹的遍歷,用過許多方法之後,最終著手於利用遞迴方法來遍歷二叉樹,遞迴演算法在實現上相較於其他的演算法來得更為簡單,但是遞迴對時間和空間的佔用其實是比較高的,所以當選擇遞迴的時候,我們應該考慮是否有更加便捷的非遞迴方法。
那麼什麼情況下我們可以有效的使用遞迴呢,遞迴和迴圈又有什麼關係呢,接下來我將會結合自身經歷粗淺的談談遞迴。
使用遞迴的條件:用一種通俗不完全的說法來講,遞迴可以說是一種呼叫自己的思想,當然這種說法並不準確,我們知道遞迴還存在交叉呼叫的情況,這裡辯不過多闡述了。既然遞迴是呼叫了自己,所以必要的一個條件就是進入遞迴的部分一定要在形式上保持一致。
遞迴和迴圈的區別在哪呢:有人說既然我已經掌握了迴圈,為什麼還要用遞迴來多此一舉呢,然而遞迴和迴圈還是有很大區別的,在我所遇到的各種問題中,所有可以用迴圈來解決的問題,用遞迴都可以很好的實現,然而用遞迴可以實現的問題,我們有時用迴圈就不能實現了。另外遞迴主要注重問題的結果,而迴圈主要關注問題的過程,我們可以從各自的實現中知道,迴圈主要是從過程中來對各個變數進行修改從而達到控制變數的結果。而遞迴則是對問題每次遞迴的結果進行討論。來達到對變數的控制。
一些經典問題關於遞迴的討論:
1.漢諾塔問題:
漢諾塔問題可以說是遞迴的一個經典問題了,很多遞迴入門的書上都有對漢諾塔問題的敘述。相信大家對這個問題已經有了很多的
瞭解了,所以我就對漢諾塔問題直接開始表述我的解決思路。
很顯然,當我們對要將n個盤子移動到目標柱子時,我們只需要考慮將n-1個盤中移動到目標柱子,明顯的,我們可以通過遞迴來解決
這個問題。
假設柱子為1,2,3(依次3為當前位置,過渡柱子,目標柱子),遞迴方法為:method(int n,1,3,2),表示為將n個盤子從1通過2移動到3
便有method(int n,1,3,2):
if(n==1) move n 從1移動到3;
else{
method(n-1,1,3,2);
method(n-1,2,3,1)這行主要是為了讓遞迴在形式上保持一致。
}
2.斐波那契數列:
如果大家覺得這個名字很數學,很高大上,不好理解的話,我建議可以看成另一個問題。兔子生孩問題(自己隨便取的名字),假設我們有一對兔子,兔子到第三個月開頭就會生下一對小兔子,如果兔子不死,求不第n個月有多少對兔子。
顯然我們可以看出兔子和對應的數量關係為:1,1,2,3,5,8,13.......,從中我們得出規律,從第三個開始,每一個就是前兩個之和,這
很顯然可以使用遞迴來實現:
method(n):
if(n==1||n==2) return 2;
return method(n-1)+method(n-2);
這樣斐波那契數列蘇烈就可以很好的實現了。
3.遍歷二叉樹:
這是在leetcode上所遇到的一個問題,其實當時是並不需要我遍歷整個二叉樹,但是處於對知識額運用,我用了遞迴的方法來
二叉樹,我這裡採用的是中序遍歷,前序和後序實現差不多,大家可以自己思考,首先TreeNode已經有題目自定了。
實現如下:
method(root)
LinkedList list = new LinkedList();
if(root==null) return;
id(root.left!=null) method(root.left);
list.add(root);
if(root.right!=null) method(root.right);