LeetCode 里面很大一部分題目都是屬於這個范圍,例如Path Sum用的就是遞歸+DFS,Path Sum2用的是遞歸+DFS+回溯
這里參考了一些網上寫得很不錯的文章,總結一下理解與模板
遞歸:就是出現這種情況的代碼: (或者說是用到了棧)
解答樹角度:在dfs遍歷一棵解答樹
優點:結構簡潔
缺點:效率低,可能棧溢出
遞歸的一般結構:
1 void f() 2 { 3 if(符合邊界條件) 4 { 5 /////// 6 return; 7 } 8 9 //某種形式的調用 10 f(); 11 }
回溯:遞歸的一種,或者說是通過遞歸這種代碼結構來實現回溯這個目的。回溯法可以被認為是一個有過剪枝的DFS過程。
解答樹角度:帶回溯的dfs遍歷一棵解答樹
回溯的一般結構:
1 void dfs(int 當前狀態) 2 { 3 if(當前狀態為邊界狀態) 4 { 5 記錄或輸出 6 return; 7 } 8 for(i=0;i<n;i++) //橫向遍歷解答樹所有子節點 9 { 10 //擴展出一個子狀態。 11 修改了全局變量 12 if(子狀態滿足約束條件) 13 { 14 dfs(子狀態) 15 } 16 恢復全局變量//回溯部分 17 } 18 }
BFS和DFS是相似。
BFS(顯式用隊列)
DFS(隱式用棧)(即遞歸)
當然,對於DFS,用遞歸可能會造成棧溢出,所以也可以更改為顯示棧。
BFS:典型例題:P101 對於二叉樹的層次遍歷,P108對於圖的走迷宮最短路徑
DFS:典型例題:P107黑白圖像
格式:將所有節點遍歷一遍,在遍歷每個節點是,DFS的遍歷該節點相關的所有節點
1 void dfs(int x, int y) 2 { 3 if(!mat[x][y] || vis[x][y]) return; // 曾經訪問過這個格子,或者當前格子是白色 4 vis[x][y] = 1; // 標記(x,y)已訪問過 5 dfs(x-1,y-1); dfs(x-1,y); dfs(x-1,y+1); 6 dfs(x-1,y); dfs(x,y+1); 7 dfs(x+1,y-1); dfs(x+1,y); dfs(x+1,y+1); // 遞歸訪問周圍的八個格子 8 } 9 主循環: 10 for(int i = 1; i <= n; i++) 11 for(int j = 1; j <= n; j++) 12 if(!vis[i][j] && mat[i][j]) 13 { 14 count++; 15 dfs(i,j); 16 } // 找到沒有訪問過的黑格
上述內容為轉載內容。