BFS

应用场景

一般用来解决最短连通路径问题。

基本思路

单源BFS:借助Queue,将源点存进Queue,然后每次从Queue的头取一个元素,将所有 unvisited neighbors加到Queue尾,依次进行,直到Queue空。

Typical BFS 写法

Queue q;
Set visited;
q.add(node);

while(q is not empty) {
    Node cur = q.poll();
    for(Node neighbor: cur.neighbors) {
        if(neighbor is not visited) {
            q.add(neighbor);
        }
    }
}

多源BFS:单源BFS的升级版。会大大减少时间复杂度。前提是,每个源的地位都是一样的。做法跟单源的类似,只不过要先把所有源存进Queue。

经典题目

323 Number of Connected Components in an Undirected Graph

// time: O(V + E + V * E) ???
public int countComponents(int n, int[][] edges) {
    List<List<Integer>> graph = buildGraph(n, edges);
    int ans = 0;
    boolean[] visited = new boolean[n];
    for (int i = 0; i < n; i++) {
        if (!visited[i]) {
            Deque<Integer> queue = new LinkedList<>();
            queue.offerLast(i);
            while (!queue.isEmpty()) {
                int cur = queue.pollFirst();
                visited[cur] = true;
                List<Integer> list = graph.get(cur);
                if (list != null) {
                    for (Integer nei : list) {
                        if (!visited[nei]) {
                            queue.offerLast(nei);
                        }
                    }
                }
            }
            ans += 1;
        }
    }
    return ans;
}

private List<List<Integer>> buildGraph(int n, int[][] edges) {
    List<List<Integer>> graph = new ArrayList<List<Integer>>();
    for (int i = 0; i < n; i++) {
        graph.add(new ArrayList<Integer>());
    }
    for (int[] edge: edges) {
        graph.get(edge[0]).add(edge[1]);
        graph.get(edge[1]).add(edge[0]);
    }
    return graph;
}

class Solution {
    private int[][] dirs = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
    
    public void wallsAndGates(int[][] rooms) {
        if (rooms == null || rooms.length == 0 || rooms[0].length == 0) return;
        int n = rooms.length;
        int m = rooms[0].length;
        Deque<int[]> queue = new LinkedList<>();
        boolean[][] visited = new boolean[n][m];
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < m; j++) {
                if (rooms[i][j] == 0) {
                    //bfs(i, j, n, m, rooms);
                    queue.offerLast(new int[] {i, j});
                    visited[i][j] = true;
                }
            }
        }
        bfs(n, m, queue, visited, rooms);
    }
    
    private void bfs(int n, int m, Deque<int[]> queue, boolean[][] visited, int[][] rooms) {
        int step = 0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            while(size-- > 0) {
                int[] cur = queue.pollFirst();
                for (int i = 0; i < dirs.length; i++) {
                    int nextRow = cur[0] + dirs[i][0];
                    int nextCol = cur[1] + dirs[i][1];
                    if (nextRow >= 0 && nextRow < n && nextCol >= 0 && nextCol < m && !visited[nextRow][nextCol] && rooms[nextRow][nextCol] > 0) {
                        visited[nextRow][nextCol] = true;
                        queue.offerLast(new int[] {nextRow, nextCol});
                    }
                }
                rooms[cur[0]][cur[1]] = step;
            }
            step++;
        }
    }
}

675. Cut Off Trees for Golf Event

// 有几个陷阱要注意:1. (0, 0)是需要进栈的,因为有可能不是先砍(0, 0)
// 2. 如果(0, 0)点是最小点,则直接砍,也就是说BFS的时候,得预先判断一下。
// 3. BFS的时候,判断neighbor是不是valid,只需要看能不能走就行。

class Solution {
    private int[][] dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};
    public int cutOffTree(List<List<Integer>> forest) {
        List<int[]> trees = new ArrayList<>();
        for (int i = 0; i < forest.size(); i++) {
            List<Integer> row = forest.get(i);
            for (int j = 0; j < row.size(); j++) {
                int val = row.get(j);
                if (val > 1) {
                    trees.add(new int[] {i, j, val});
                }
            }
        }
        Collections.sort(trees, (int[] a, int[] b) -> (a[2] - b[2]));
        int sr = 0, sc = 0;
        int ans = 0;
        for (int[] tree: trees) {
            int dist = getDistance(sr, sc, tree[0], tree[1], forest);
            //System.out.println(dist);
            if (dist == -1) return -1;
            ans += dist;
            sr = tree[0];
            sc = tree[1];
        }
        return ans;
    }
    
    // BFS to find shortest path
    private int getDistance(int sr, int sc, int dr, int dc, List<List<Integer>> forest) {
        if (sr == dr && sc == dc) {
            return 0;
        }
        int n = forest.size();
        int m = forest.get(0).size();
        Deque<int[]> queue = new LinkedList<>();
        boolean[][] visited = new boolean[n][m];
        queue.offerLast(new int[] {sr, sc});
        visited[sr][sc] = true;
        int step = 1;
        while (!queue.isEmpty()) {
            int size = queue.size();
            while (size-- > 0) {
                int[] cur = queue.pollFirst();
                for (int i = 0; i < dirs.length; i++) {
                    int nextRow = cur[0] + dirs[i][0];
                    int nextCol = cur[1] + dirs[i][1];
                    if (nextRow == dr && nextCol == dc) {
                        return step;
                    }
                    if (nextRow >= 0 && nextRow < n && nextCol >= 0 && nextCol < m && !visited[nextRow][nextCol] && forest.get(nextRow).get(nextCol) > 0) {
                        visited[nextRow][nextCol] = true;
                        queue.offerLast(new int[] {nextRow, nextCol});
                    }
                }
            }
            step++;
        }
        return -1;
    }
}

863. All Nodes Distance K in Binary Tree

// 类似于 KNN,以 target 为中心,做BFS

class Solution {
    class MyNode {
        int val;
        MyNode left, right, parent;
        public MyNode(int x) {
            val = x;
        }
    }
    
    public List<Integer> distanceK(TreeNode root, TreeNode target, int K) {
        List<Integer> ans = new ArrayList<>();
        
		// Rebuild a binary tree with the parent property
        MyNode[] array = new MyNode[] {null};
        MyNode myNode = rebuild(root, null, target, array);
        // New Target Node
		MyNode targetNode = array[0];
        
		// Start from New Target Node, do BFS
		// Stop at distance K
        Deque<MyNode> queue = new LinkedList<>();
        Set<Integer> visited = new HashSet<>();
        queue.offerLast(targetNode);
        visited.add(targetNode.val);
        
        while (K-- > 0) {
            int size = queue.size();
            while (size-- > 0) {
                MyNode cur = queue.pollFirst();
                if (cur.left != null && !visited.contains(cur.left.val)) {
                    visited.add(cur.left.val);
                    queue.offerLast(cur.left);
                }
                if (cur.right != null && !visited.contains(cur.right.val)) {
                    visited.add(cur.right.val);
                    queue.offerLast(cur.right);
                }
                if (cur.parent != null && !visited.contains(cur.parent.val)) {
                    visited.add(cur.parent.val);
                    queue.offerLast(cur.parent);
                }
            }
        }
        
		// Remaining Nodes in queue are all distance K from New Target Node
        while (!queue.isEmpty()) {
            ans.add(queue.pollFirst().val);
        }
        
        return ans;
    }
    
    private MyNode rebuild(TreeNode node, MyNode parent, TreeNode target, MyNode[] array) {
        if (node == null) return null;
        
        MyNode myNode = new MyNode(node.val);
        myNode.left = rebuild(node.left, myNode, target, array);
        myNode.right = rebuild(node.right, myNode, target, array);
        myNode.parent = parent;
        
        if (target.val == node.val) {
            array[0] = myNode;
        }
        
        return myNode;
    }
}

Last updated