思路

应用场景:最短路径。对比DFS,BFS所有路线齐头并进,保证第一次到达终点的时候走的步数最少,并且不用完整遍历整个树或者图。但是空间复杂度高,需要队列作为辅助。

框架

  1. // 计算从起点 start 到终点 target 的最近距离
  2. int BFS(Node start, Node target) {
  3. Queue<Node> q; // 核心数据结构
  4. Set<Node> visited; // 避免走回头路
  5. q.offer(start); // 将起点加入队列
  6. visited.add(start);
  7. int step = 0; // 记录扩散的步数
  8. while (q not empty) {
  9. int sz = q.size();
  10. /* 将当前队列中的所有节点向四周扩散 */
  11. for (int i = 0; i < sz; i++) {
  12. Node cur = q.poll();
  13. /* 划重点:这里判断是否到达终点 */
  14. if (cur is target)
  15. return step;
  16. /* 将 cur 的相邻节点加入队列 */
  17. for (Node x : cur.adj())
  18. if (x not in visited) {
  19. q.offer(x);
  20. visited.add(x);
  21. }
  22. }
  23. /* 划重点:更新步数在这里 */
  24. step++;
  25. }
  26. }

还有一种双向bfs优化,知道起点和

例题

111. 二叉树的最小深度

  1. /**
  2. * Definition for a binary tree node.
  3. * public class TreeNode {
  4. * int val;
  5. * TreeNode left;
  6. * TreeNode right;
  7. * TreeNode() {}
  8. * TreeNode(int val) { this.val = val; }
  9. * TreeNode(int val, TreeNode left, TreeNode right) {
  10. * this.val = val;
  11. * this.left = left;
  12. * this.right = right;
  13. * }
  14. * }
  15. */
  16. class Solution {
  17. public int minDepth(TreeNode root) {
  18. if (root == null) return 0;
  19. Queue<TreeNode> queue = new LinkedList<>();
  20. queue.add(root);
  21. int depth = 1;
  22. while (!queue.isEmpty()) {
  23. // 这一层节点数量
  24. int size = queue.size();
  25. for (int i = 0; i < size; ++i) {
  26. TreeNode node = queue.poll();
  27. if (node.left == null && node.right == null) return depth;
  28. if (node.left != null) queue.add(node.left);
  29. if (node.right != null) queue.add(node.right);
  30. }
  31. depth++;
  32. }
  33. return depth;
  34. }
  35. }

752. 打开转盘锁

转动一次4位转盘一共有八种方式,所以每个状态节点相邻有八个状态节点,这样就能将问题转化成广度搜索问题。搜到的第一个符合要求的状态时的步数就是答案。
deads和visited的作用实际上一样,也可以一开始就将deadends里面的状态加入visited中,效果相同,都是遇到了就不理睬它的相邻状态节点就好了。

  1. class Solution {
  2. public int openLock(String[] deadends, String target) {
  3. // bfs辅助队列
  4. Queue<String> queue = new LinkedList<>();
  5. queue.offer("0000");
  6. // 死亡情况set
  7. Set<String> deads = new HashSet<>();
  8. for (String deadend : deadends) deads.add(deadend);
  9. // 记录走过的路
  10. Set<String> visited = new HashSet<>();
  11. visited.add("0000");
  12. // 从起点开始步骤数
  13. int stepNum = 0;
  14. while (!queue.isEmpty()) {
  15. int sz = queue.size();
  16. // 向节点周围扩散
  17. for (int i = 0; i < sz; ++i) {
  18. String cur = queue.poll();
  19. // 判断dead和target,遇到dead就不能继续走了,遇到target就直接返回当前步数
  20. if (deads.contains(cur)) continue;
  21. if (cur.equals(target)) return stepNum;
  22. // 周围节点(八个)加入队列(四个wheels分别 + - )
  23. for (int j = 0; j < 4; ++j) {
  24. String up = plusOne(cur, j);
  25. // 访问过的状态就不考虑了,避免死循环
  26. if (!visited.contains(up)) {
  27. queue.offer(up);
  28. visited.add(up);
  29. }
  30. String down = minusOne(cur, j);
  31. if (!visited.contains(down)) {
  32. queue.offer(down);
  33. visited.add(down);
  34. }
  35. }
  36. }
  37. ++stepNum;
  38. }
  39. // 无法实现
  40. return -1;
  41. }
  42. // No.i wheel +1
  43. private String plusOne(String lock, int i) {
  44. char[] arr = lock.toCharArray();
  45. if (arr[i] == '9') arr[i] = '0';
  46. else arr[i]++;
  47. return new String(arr);
  48. }
  49. // No.i wheel -1
  50. private String minusOne(String lock, int i) {
  51. char[] arr = lock.toCharArray();
  52. if (arr[i] == '0') arr[i] = '9';
  53. else arr[i]--;
  54. return new String(arr);
  55. }
  56. }