算法 递归与回溯
遞歸
遞歸是利用方法棧幀后進先出的特點。先進入的方法棧幀等待后進入的方法棧幀計算結果。例如:f(n)=f(n-1)+1,f(n)等待f(n-1)的結果,依次遞歸向下優先算出最低層結果后,再依次返回根據下層結果計算。
遞:一層一層深入(依次執行前置代碼),直到到達遞歸終止條件(一定要有終止條件,不再執行自己)。
等待下層方法棧幀執行完成/return結果......
歸:再從底層一層一層返回(依次執行后置代碼)。利用JAVA方法棧幀局部變量獨立的特性,保證退回棧幀時狀態為原始狀態。
遞歸也是循環的一種表現,不過比循環更容易執行多層回退、前序后序操作。但是遞歸因為要重復的創建棧幀所以效率沒有循環高。
遞歸思想,開發人員只要把設計重心放到設計一步操作的統一模板即可,包含進入到這一步執行的代碼,是否可以進入下一步,返回當前步驟后繼續執行的代碼。
循環代替
一般循環也可以用while循環執行回退,但是比較麻煩。需要借助一個Stack數據結構保存各步狀態,并且手動遞增和回退,并保證正確性。
?
常涉及的算法思想
分治思想:
快速排序:典型的遞歸前置思想,先執行取中分邊,再左右向下遞歸
歸并排序:典型的遞歸后置思想,先取中左右向下遞歸,再從最底層一層層向上執行歸并。
回溯思想:
DFS,斐波那契.....等等
?
2 復用避免重復計算
? ?可以適當配和動態規劃思想,遞歸時可以把各步結果保存,可以復用。?斐波那契數列就是典型例子
3? 斐波那契數
//遞歸方式實現斐波那契數public static long rec_fib(long i) {long result = 0;if(i <= 0) return 0; //遞歸終止if(i == 1 || i == 2) //遞歸終止result = 1;else {System.out.println("遞歸前置");result = rec_fib(i-1) //返回繼續 <=======> 進入下層+ rec_fib(i-2); //返回繼續 <=======> 進入下層System.out.println("遞歸后置");}return result;}回溯算法
回溯算法很符合人類思維邏輯,適用范圍非常廣泛。
回溯算法是一種試探性算法,也是窮舉法,利用DFS的解決思路,把整個問題想成一個樹形/圖形節點關系,不同的可能代表不同節點分支。從一個節點開始以DFS一步一步向下試探,不滿足條件/目標則退回上一步節點探性其他分支,若沒有剩余分支再退回上一步。其也是遞歸特性的一種經典表現。
明確終止向下試探的邊際條件,?設計遞歸前置代碼處理準備進入下一步之前的工作,遞歸后置代碼處理再次退回當前節點時當前節點需要繼續執行的工作。
典型問題:leetcode39、78
給定一組不含重復元素的整數數組?nums={0,1,2},返回該數組所有可能的子集(冪集)。
按照代碼執行順序:
[],[0],[0,1],[0,1,2],[0,2],[1],?[1,2],[2]
第一層循環:確定子集首位,當遇到第一個選項分支時直接遞歸進入第二層;
第二層循環:確定第二位 ......以此類推,沒有可/未選分支了,再退回上一位,找其他分支。
public static void main(String[] args) {int[] nums = {0,1,2};System.out.println(subsets(nums));}public static List<List<Integer>> subsets(int[] nums) {List<List<Integer>> result = new ArrayList();//結果集(所有子集)List<Integer> temp = new ArrayList();//記錄到當前節點的路過節點(當前路徑)dfs(result,temp,nums,0);return result;}public static void dfs(List<List<Integer>> result, List<Integer> temp, int nums[], int index){result.add(new ArrayList<Integer>(temp));//temp添加到結果集中//從index位置向后for (int i = index; i < nums.length; i++) {//添加第i個數進入temp中temp.add(nums[i]);//進入到下一層,將temp添加到結果集中并添加下一個數dfs(result,temp,nums,i+1); //返回繼續 <=======> 進入下層//從下層返回后,把最新添加的一個數刪掉繼續循環(temp手動回退到本層原狀態)temp.remove(temp.size()-1);}//循環完返回上一層遞歸}?
轉載于:https://www.cnblogs.com/sw008/p/11054307.html
總結
- 上一篇: JavaScrpt简单介绍
- 下一篇: 1.void main