DFS 模板

一句话说明

DFS 沿着一条路尽量走到底,走不动再回退,所以它天然适合递归、回溯和连通块搜索。

模板适用场景

  • 图遍历
  • 连通块染色
  • 岛屿问题
  • 需要深入一条路径到底

如果题目要求最少步数,优先想 BFS,不要本能套 DFS。

Go 模板:递归 DFS

func DFSRecursive(graph [][]int, start int) []int {
    visited := make([]bool, len(graph))
    order := []int{}
 
    var dfs func(node int)
    dfs = func(node int) {
        if visited[node] {
            return
        }
 
        visited[node] = true
        order = append(order, node)
 
        for _, next := range graph[node] {
            dfs(next)
        }
    }
 
    dfs(start)
    return order
}

Go 模板:栈实现 DFS

func DFSIterative(graph [][]int, start int) []int {
    visited := make([]bool, len(graph))
    order := []int{}
    stack := []int{start}
 
    for len(stack) > 0 {
        node := stack[len(stack)-1]
        stack = stack[:len(stack)-1]
 
        if visited[node] {
            continue
        }
        visited[node] = true
        order = append(order, node)
 
        for i := len(graph[node]) - 1; i >= 0; i-- {
            next := graph[node][i]
            if !visited[next] {
                stack = append(stack, next)
            }
        }
    }
 
    return order
}

什么时候优先改成迭代

如果图或树的深度可能达到 10^5 量级,递归栈就有风险。
这时显式栈版本更稳。

Go 模板:网格 DFS 染色

func FloodFill(grid [][]byte, row, col int) {
    rows, cols := len(grid), len(grid[0])
    dirs := [][2]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}
 
    var dfs func(r, c int)
    dfs = func(r, c int) {
        if r < 0 || r >= rows || c < 0 || c >= cols {
            return
        }
        if grid[r][c] != '1' {
            return
        }
 
        grid[r][c] = '0'
        for _, d := range dirs {
            dfs(r+d[0], c+d[1])
        }
    }
 
    dfs(row, col)
}

易错点

DFS 模板最容易错的地方

  • 图有环时必须维护 visited。
  • 无向图如果不想单独写 visited,也至少要避免走回父节点。
  • 递归写法在深图上可能爆栈,别忽略数据范围。

相关主题


返回:算法模板