DFS(深度优先搜索)和 BFS(广度优先搜索)的区别

如果我们使用 DFS/BFS 只是为了遍历一棵树、一张图上的所有结点的话,那么 DFS 和 BFS 的能力没什么差别,我们当然更倾向于更方便写、空间复杂度更低的 DFS 遍历。不过,某些使用场景是 DFS 做不到的,只能使用 BFS 遍历。例如:「层序遍历」、「最短路径」。
DFS 遍历使用递归

  1. void dfs(TreeNode root) {
  2. if (root == null) {
  3. return;
  4. }
  5. dfs(root.left);
  6. dfs(root.right);
  7. }

BFS 遍历使用队列数据结构:

  1. void bfs(TreeNode root) {
  2. Queue<TreeNode> queue = new ArrayDeque<>();
  3. queue.add(root);
  4. while (!queue.isEmpty()) {
  5. TreeNode node = queue.poll(); // Java 的 pop 写作 poll()
  6. if (node.left != null) {
  7. queue.add(node.left);
  8. }
  9. if (node.right != null) {
  10. queue.add(node.right);
  11. }
  12. }
  13. }

102. 二叉树的层序遍历

给你一个二叉树,请你返回其按 层序遍历 得到的节点值。 (即逐层地,从左到右访问所有节点)。

思路:
BFS 和 DFS 都可以。
DFS,关键点是设置 level 参数,比较当前层级 level 和 结果集 res 的长度,如果 level 大于等于结果集 res 的长度,则说明当前层级遍历已经结束,需要开始遍历下一层级。
BFS,关键点是在队列循环的过程中,获取当前队列的长度,然后进行二级循环,这样二级循环中添加的值都来自同一层级的结点,并把下一层的结点加入到队列末尾。

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode(int x) { val = x; }
  8. * }
  9. */
  10. class Solution {
  11. public List<List<Integer>> levelOrder(TreeNode root) {
  12. List<List<Integer>> res = new ArrayList<>();
  13. dfs(res, root, 0);
  14. return res;
  15. }
  16. private void dfs(List<List<Integer>> res, TreeNode node, int level) {
  17. if (node == null) {
  18. return;
  19. }
  20. List<Integer> cur;
  21. if (level >= res.size()) {
  22. cur = new ArrayList<>();
  23. cur.add(node.val);
  24. res.add(cur);
  25. } else {
  26. cur = res.get(level);
  27. cur.add(node.val);
  28. }
  29. dfs(res, node.left, level+1);
  30. dfs(res, node.right, level+1);
  31. }
  32. }
  1. class Solution {
  2. public List<List<Integer>> levelOrder(TreeNode root) {
  3. List<List<Integer>> res = new ArrayList<>();
  4. if (root == null) return res;
  5. Queue<TreeNode> queue = new LinkedList<>();
  6. queue.offer(root);
  7. while (!queue.isEmpty()) {
  8. int size = queue.size();
  9. List<Integer> temp = new ArrayList<>(size);
  10. for (int i = 0; i < size; i++) {
  11. TreeNode cur = queue.poll();
  12. temp.add(cur.val);
  13. if (cur.left != null) {
  14. queue.offer(cur.left);
  15. }
  16. if (cur.right != null) {
  17. queue.offer(cur.right);
  18. }
  19. }
  20. res.add(new ArrayList<>(temp));
  21. }
  22. return res;
  23. }
  24. }

279. 完全平方数

给定正整数 n,找到若干个完全平方数(比如 1, 4, 9, 16, ...)使得它们的和等于 n。你需要让组成和的完全平方数的个数最少。

思路:
BFS,将完全平方数加入队列,逐渐减小 head 的值,直到满足 j j == head。
动态规划,dp[i] 的值为 dp[i-j
j]+1 中最小的那个。

  1. class Solution {
  2. public int numSquares(int n) {
  3. Queue<Integer> queue = new LinkedList<>();
  4. queue.offer(n);
  5. boolean[] visited = new boolean[n + 1];
  6. int step = 1;
  7. while (!queue.isEmpty()) {
  8. int size = queue.size();
  9. for (int i = 0; i < size; i++) {
  10. int head = queue.poll();
  11. for (int j = 1; j * j <= head; j++) {
  12. if (j * j == head) {
  13. return step;
  14. }
  15. int next = head - j * j;
  16. if (!visited[next]) {
  17. queue.offer(next);
  18. visited[next] = true;
  19. }
  20. }
  21. }
  22. step++;
  23. }
  24. return -1;
  25. }
  26. }
class Solution {
    public int numSquares(int n) {
        int[] dp = new int[n + 1];
        for (int i = 1; i <= n; i++) {
            int res = Integer.MAX_VALUE;
            for (int j = 1; i - j * j >= 0; j++) {
                res = Math.min(1 + dp[i - j * j], res);
            }
            dp[i] = res;
        }

        return dp[n];
    }
}

练习:

662. 二叉树最大宽度

给定一个二叉树,编写一个函数来获取这个树的最大宽度。树的宽度是所有层中的最大宽度。这个二叉树与满二叉树(full binary tree)结构相同,但一些节点为空。

每一层的宽度被定义为两个端点(该层最左和最右的非空节点,两端点间的null节点也计入长度)之间的长度。

思路:

/**
 * Definition for a binary tree node.
 * public class TreeNode {
 *     int val;
 *     TreeNode left;
 *     TreeNode right;
 *     TreeNode() {}
 *     TreeNode(int val) { this.val = val; }
 *     TreeNode(int val, TreeNode left, TreeNode right) {
 *         this.val = val;
 *         this.left = left;
 *         this.right = right;
 *     }
 * }
 */
class Solution {
    public int widthOfBinaryTree(TreeNode root) {
        if (root == null) return 0;
        Queue<TreeNode> s = new LinkedList<>();
        Queue<Integer> q = new LinkedList<>();
        s.add(root);
        q.add(1);
        int max = 1;
        while (s.size() != 0) {
            int len = s.size();
            int start = q.peek();
            for (int i = 0; i < len; i++) {
                TreeNode t = s.poll();
                int index = q.poll();
                if (i == len - 1) max = Math.max(max, index - start + 1);
                if (t.left != null) {
                    s.offer(t.left);
                    q.offer(index * 2 - 1);
                }
                if (t.right != null) {
                    s.offer(t.right);
                    q.offer(index * 2);
                }
            }
        }
        return max;
    }
}

993. 二叉树的堂兄弟节点