🚀 DFS、BFS 与回溯算法模板整理


一、图的 DFS 模板(递归)

void dfs(Node node, Set<Node> visited) {
    // 1. 终止条件
    if (node == null || visited.contains(node)) return;

    // 2. 标记访问
    visited.add(node);

    // 3. 访问当前节点
    System.out.println(node.val);

    // 4. 访问邻居节点
    for (Node neighbor : node.neighbors) {
        dfs(neighbor, visited);
    }
}

说明

  • 使用 递归 + visited 集合 防止重复访问。
  • 用于:图的连通性检测、路径搜索、环检测等。
class Node {
    String val;
    List<Node> neighbors;

    Node(String val) {
        this.val = val;
        this.neighbors = new ArrayList<>();
    }
}

二、树的 DFS 模板(递归)

void dfs(TreeNode root) {
    if (root == null) return;

    // 前序位置:访问节点
    System.out.println(root.val);

    dfs(root.left);
    dfs(root.right);
}

遍历类型说明

  • 前序遍历:在递归前访问节点。
  • 中序遍历:在左子树后、右子树前访问。
  • 后序遍历:递归结束后访问节点。

三、图的 BFS 模板(通用)

void bfs(Node start) {
    Queue<Node> queue = new LinkedList<>();
    Set<Node> visited = new HashSet<>();

    queue.offer(start);
    visited.add(start);

    while (!queue.isEmpty()) {
        Node node = queue.poll();
        System.out.println(node.val);

        for (Node neighbor : node.neighbors) {
            if (!visited.contains(neighbor)) {
                visited.add(neighbor);
                queue.offer(neighbor);
            }
        }
    }
}

要点

  • 使用 队列(FIFO) 实现层级遍历。
  • 每一层的节点都在队列中。
  • 适用于 最短路径、层序遍历 等问题。

四、BFS 模板(带层次遍历)

void bfsWithLevel(Node start) {
    Queue<Node> queue = new LinkedList<>();
    Set<Node> visited = new HashSet<>();

    queue.offer(start);
    visited.add(start);
    int level = 0;

    while (!queue.isEmpty()) {
        int size = queue.size();  // 当前层的节点数
        System.out.print("Level " + level + ": ");

        for (int i = 0; i < size; i++) {
            Node node = queue.poll();
            System.out.print(node.val + " ");

            for (Node neighbor : node.neighbors) {
                if (!visited.contains(neighbor)) {
                    visited.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
        System.out.println();
        level++;
    }
}

五、树的 BFS 模板(层序遍历)

void levelOrder(TreeNode root) {
    if (root == null) return;

    Queue<TreeNode> queue = new LinkedList<>();
    queue.offer(root);

    while (!queue.isEmpty()) {
        int size = queue.size();
        for (int i = 0; i < size; i++) {
            TreeNode node = queue.poll();
            System.out.print(node.val + " ");

            if (node.left != null) queue.offer(node.left);
            if (node.right != null) queue.offer(node.right);
        }
        System.out.println();
    }
}

六、DFS vs BFS 对比

维度DFSBFS
数据结构栈 / 递归队列
访问顺序深入到底再回溯一层层扩展
适用场景连通性检测、路径搜索、拓扑排序最短路径、层次遍历
空间复杂度O(V)(递归深度)O(V)(队列大小)
实现难度简洁但容易栈溢出稍复杂但稳定

七、模板使用技巧总结

技巧说明
✅ visited 一定要在入队/入栈时标记避免重复加入
✅ 图中有环必须判重否则无限循环
✅ 树结构可省略 visited因为树无环
✅ BFS 常配合“层计数”解决最短路径常见于迷宫、网络传播
✅ DFS 可配合回溯(Backtracking)常见于排列组合、路径问题

八、回溯算法(Backtracking)模板

回溯是一种 暴力搜索 + 剪枝优化 的算法思想。
其本质是:

DFS(深度优先搜索) + 状态恢复

通俗地说:

“选中一个 → 递归探索 → 不行撤销 → 换下一个”

通用模板(带剪枝优化)

void backtrack(路径 path, int start, 选择列表 choices) {
    if (满足结束条件) {
        保存结果(path);
        return;
    }

    for (int i = start; i < choices.length; i++) {
        // 剪枝:若不满足条件,直接跳过
        if (不合法(choices[i])) continue;

        // 做选择
        path.add(choices[i]);

        // 进入下一层
        backtrack(path, i + 1, choices);

        // 撤销选择(回溯)
        path.remove(path.size() - 1);
    }
}

九、回溯算法常见应用

类型示例关键点
组合问题LeetCode 77 组合不考虑顺序,使用 start 控制重复
排列问题LeetCode 46 全排列考虑顺序,需 used[] 数组标记
子集问题LeetCode 78 子集每层都可以收集结果
棋盘搜索N 皇后、数独二维递归 + 剪枝关键
字符串切割分割回文串注意递归中切割位置变化

更多推荐