LeetCode 上经典的 DFS 题目及 Golang 实现与模板总结 DFS(深度优先搜索)是算法面试中的常见题型,下面我将总结 LeetCode 上一些经典的 DFS 题目,并用 Golang 实现,最后提炼出通用的 DFS 解题模板。
经典 DFS 题目分类及 Golang 实现 1. 二叉树遍历类 题目 94. 二叉树的中序遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 func inorderTraversal (root *TreeNode) []int { var res []int var dfs func (node *TreeNode) dfs = func (node *TreeNode) { if node == nil { return } dfs(node.Left) res = append (res, node.Val) dfs(node.Right) } dfs(root) return res }
2. 排列组合类 题目 46. 全排列 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 func permute (nums []int ) [][]int { var res [][]int visited := make ([]bool , len (nums)) var dfs func (path []int ) dfs = func (path []int ) { if len (path) == len (nums) { tmp := make ([]int , len (path)) copy (tmp, path) res = append (res, tmp) return } for i := 0 ; i < len (nums); i++ { if visited[i] { continue } visited[i] = true path = append (path, nums[i]) dfs(path) path = path[:len (path)-1 ] visited[i] = false } } dfs([]int {}) return res }
3. 岛屿问题类 题目 200. 岛屿数量 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 func numIslands (grid [][]byte ) int { if len (grid) == 0 { return 0 } count := 0 m, n := len (grid), len (grid[0 ]) var dfs func (i, j int ) dfs = func (i, j int ) { if i < 0 || j < 0 || i >= m || j >= n || grid[i][j] != '1' { return } grid[i][j] = '0' dfs(i+1 , j) dfs(i-1 , j) dfs(i, j+1 ) dfs(i, j-1 ) } for i := 0 ; i < m; i++ { for j := 0 ; j < n; j++ { if grid[i][j] == '1' { count++ dfs(i, j) } } } return count }
4. 回溯类问题 题目 39. 组合总和 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 func combinationSum (candidates []int , target int ) [][]int { var res [][]int var dfs func (start int , path []int , sum int ) dfs = func (start int , path []int , sum int ) { if sum == target { tmp := make ([]int , len (path)) copy (tmp, path) res = append (res, tmp) return } if sum > target { return } for i := start; i < len (candidates); i++ { path = append (path, candidates[i]) dfs(i, path, sum+candidates[i]) path = path[:len (path)-1 ] } } dfs(0 , []int {}, 0 ) return res }
Golang DFS 通用模板 根据以上题目,可以总结出 DFS 的通用模板:
递归回溯模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 func problemFunction (params) [][]resultType { var res [][]resultType var dfs func (path []resultType, otherParams...) dfs = func (path []resultType, otherParams...) { if meetCondition { tmp := make ([]resultType, len (path)) copy (tmp, path) res = append (res, tmp) return } for _, choice := range choices { if !isValid(choice) { continue } path = append (path, choice) markAsVisited(choice) dfs(path, updatedParams...) path = path[:len (path)-1 ] markAsUnvisited(choice) } } dfs(initialPath, initialParams...) return res }
网格/矩阵DFS模板 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 func gridProblem (grid [][]byte ) int { if len (grid) == 0 { return 0 } m, n := len (grid), len (grid[0 ]) count := 0 var dfs func (i, j int ) dfs = func (i, j int ) { if i < 0 || j < 0 || i >= m || j >= n || grid[i][j] != targetValue { return } grid[i][j] = markedValue dfs(i+1 , j) dfs(i-1 , j) dfs(i, j+1 ) dfs(i, j-1 ) } for i := 0 ; i < m; i++ { for j := 0 ; j < n; j++ { if grid[i][j] == targetValue { count++ dfs(i, j) } } } return count }
其他经典DFS题目推荐 子集 电话号码的字母组合 单词搜索 课程表 (拓扑排序) 路径总和 III 目标和 岛屿的最大面积 图像渲染 路径总和 II 求根到叶子节点数字和 DFS的关键在于理解递归的思想,明确递归的终止条件,以及在递归前后做好状态的保存和恢复(回溯)。掌握这些模板后,可以解决大部分DFS相关问题。