LeetCode Brush Questions: BFS

guide

Explain the
comparison between BFS and DFS

DFS keywords: recursion/stack + all solutions The
implementation of DFS relies heavily on stack/recursion, and it simply solves the problem of how to traverse all elements and seek the "end point".
However, although DFS can find the arrival path, it cannot find the shortest path. To solve this problem, a BFS (breadth first traversal) algorithm is given.
The difference with DFS is that this time it is no longer going to each bifurcation one by one, but all, traversing at the same time, until the end is found, the corresponding "number of layers" is the number of steps required for the shortest path. The
above solution Among them, if you need to process all elements in the current queue (that is, when you need a hierarchical concept), you need to add a for (i<size) loop.
If you only process one element in the queue at a time (no hierarchical concept), you don’t need to add for cycle

BFS universal solution

int BFS(Node root, Node target) {
    
    
    Queue<TreeNode> queue = new ArrayDeque<>();  // 建立队列
    int step = 0;       // 建立行动步数,通常用这个作为最短路径的返回值
    // initialize
    queue.add(root);
    // BFS
    while (!queue.isEmpty()) {
    
    
        step = step + 1;
        // 记录此时的队列大小,也即此层元素的多少
        int size = queue.size();
        for (int i = 0; i < size; ++i) {
    
     //遍历此层的所有元素
            Node cur = queue.poll();
            return step if cur is target;
            for (Node next : the neighbors of cur) {
    
    
                queue.offer(next);       //加入查找的方向,将下一层元素加入到队列中
            }
        }
    }
    return -1;          // 没有找到目标返回-1
}

example

102. Tree level traversal: standard solution

Insert picture description here

Reference:
https://leetcode-cn.com/problems/binary-tree-level-order-traversal/solution/bfs-de-shi-yong-chang-jing-zong-jie-ceng-xu-bian-l/

class Solution {
    
    
    public List<List<Integer>> levelOrder(TreeNode root) {
    
    
        List<List<Integer>> res = new LinkedList<>();
        BFS(root, res);
        return res;
    }
 
    private void BFS(TreeNode treeNode, List<List<Integer>> res) {
    
    
        if (treeNode == null) {
    
    
            return;
        }
        Queue<TreeNode> queue = new LinkedList<>();
        queue.offer(treeNode);
        while (!queue.isEmpty()) {
    
    
            List<Integer> level = new LinkedList<>();
            int n = queue.size(); // 由于下方queue会一直offer,所以这里只能int提前存储下size
            for(int i = 0; i < n; i++) {
    
     // 只是为了完成本层遍历,无实际作用
                TreeNode tmp = queue.poll();
                if(tmp != null) {
    
    
                    level.add(tmp.val);
                    queue.offer(tmp.left);
                    queue.offer(tmp.right);
                }
            }
            if(level.size() > 0) {
    
    
 res.add(level); // 由于上方的level每次都是新new的,因此无需下方这种写法
                // res.add(new LinkedList<>(level));  // 这种常常用于level是传入进来的参数,防止堆污染
            }
        }
    }
}

zigzag version: deque
Insert picture description here

public List<List<Integer>> zigzagLevelOrder(TreeNode root) {
    
    
        List<List<Integer>> ans = new LinkedList<List<Integer>>();
        if (root == null) {
    
    
            return ans;
        }
 
        Queue<TreeNode> nodeQueue = new LinkedList<TreeNode>();
        nodeQueue.offer(root);
        boolean isOrderLeft = true;
 
        while (!nodeQueue.isEmpty()) {
    
    
            Deque<Integer> levelList = new LinkedList<Integer>();
            int size = nodeQueue.size();
            for (int i = 0; i < size; ++i) {
    
    
                TreeNode curNode = nodeQueue.poll();
                if (isOrderLeft) {
    
    
                    levelList.offerLast(curNode.val);
                } else {
    
    
                    levelList.offerFirst(curNode.val);
                }
                if (curNode.left != null) {
    
    
                    nodeQueue.offer(curNode.left);
                }
                if (curNode.right != null) {
    
    
                    nodeQueue.offer(curNode.right);
                }
            }
            ans.add(new LinkedList<Integer>(levelList));
            isOrderLeft = !isOrderLeft;
        }
 
        return ans;
    }

207. Curriculum: Topological Sorting

Insert picture description here
https://leetcode-cn.com/problems/course-schedule/
Topological Sorting:
Answer:
https://leetcode-cn.com/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution /
Reference article: The storage structure of graphs and the realization of topological sorting
https://www.jianshu.com/p/cd24cfb6c8d0

DFS version answer:

List<List<Integer>> edges;
    int[] visited; // 状态数组。0:未处理;1:正在搜索;2:已经完成
    boolean valid = true;  // 结果存储
 
    public boolean canFinish(int numCourses, int[][] prerequisites) {
    
    
        edges = new ArrayList<List<Integer>>();
        for (int i = 0; i < numCourses; ++i) {
    
    
            edges.add(new ArrayList<Integer>());
        }
        visited = new int[numCourses];
        for (int[] info : prerequisites) {
    
    
            edges.get(info[1]).add(info[0]); // 邻接表的构建,注意直接get.add
        }
        for (int i = 0; i < numCourses && valid; ++i) {
    
     // 剪枝
            if (visited[i] == 0) {
    
    
                dfs(i);
            }
        }
        return valid;
    }
 
    public void dfs(int u) {
    
    
        visited[u] = 1; // 对当前处理位置做标记
        for (int v: edges.get(u)) {
    
    
            if (visited[v] == 0) {
    
    
                dfs(v); // 所有的子节点都满足拓扑排序,则本次处理节点必然满足。
                if (!valid) {
    
    
                    return; // 直接返回,同时保留了当前为1的状态
                }
            } else if (visited[v] == 1) {
    
    
                valid = false;
                return;
            }
        }
        visited[u] = 2; // 当前处理完成:这里不再是清理标记而是替换为另一种状态
    }

BFS version answer;

class Solution {
    
    
    List<List<Integer>> edges;
    int[] indeg; // 入度表
 
    public boolean canFinish(int numCourses, int[][] prerequisites) {
    
    
        edges = new ArrayList<List<Integer>>();
        for (int i = 0; i < numCourses; ++i) {
    
    
            edges.add(new ArrayList<Integer>());
        }
        indeg = new int[numCourses];
        for (int[] info : prerequisites) {
    
    
            edges.get(info[1]).add(info[0]);
            ++indeg[info[0]];
        }
 
        Queue<Integer> queue = new LinkedList<Integer>();
        for (int i = 0; i < numCourses; ++i) {
    
    
            if (indeg[i] == 0) {
    
    
                queue.offer(i); // 第一批入度为0的节点进入队列
            }
        }
 
        int visited = 0;
        while (!queue.isEmpty()) {
    
    
            ++visited;
            int u = queue.poll();
            for (int v: edges.get(u)) {
    
    
                --indeg[v];
                if (indeg[v] == 0) {
    
    
                    queue.offer(v); // 第二批入度为0的表进入队列
                }
            }
        }
 
        return visited == numCourses;
    }
}

994. Rotten Oranges: Multiple BFS

https://leetcode-cn.com/problems/rotting-oranges/solution/fu-lan-de-ju-zi-by-leetcode-solution/

Multi-source breadth first search

class Solution {
    
    
        // dr,dc 配合使用得到 grid[r][c] 上grid[r-1][c]左grid[r][c-1]下grid[r+1][c]右grid[r][c+1]的元素
        int[] dr = new int[]{
    
    -1, 0, 1, 0};  // 代指四个方向,左[-1,0],上[0,-1],右[1,0],下[0,1]
        int[] dc = new int[]{
    
    0, -1, 0, 1};
public int orangesRotting(int[][] grid) {
    
    
            // 获取二维数组的行数row 和 列数 column
            int R = grid.length, C = grid[0].length;
                          // queue : all starting cells with rotten oranges
            Queue<Integer> queue = new ArrayDeque();
            Map<Integer, Integer> depth = new HashMap();
            for (int r = 0; r < R; ++r)
                for (int c = 0; c < C; ++c)
                    if (grid[r][c] == 2) {
    
    
                        int code = r * C + c;  // 转化为索引唯一的一维数组
                        queue.add(code); //存储腐烂橘子
                        depth.put(code, 0); //存储橘子变为腐烂时的时间,key为橘子的一维数组下标,value为变腐烂的时间
                    }
 
                          int ans = 0; // 存储最终结果
            while (!queue.isEmpty()) {
    
     // 处理所有感染者
                int code = queue.remove();
                int r = code / C, c = code % C;
                for (int k = 0; k < 4; ++k) {
    
    
                    // grid位置获取方式,四个方向,四种策略
                    int nr = r + dr[k];
                    int nc = c + dc[k]; 
                    if (0 <= nr && nr < R && 0 <= nc && nc < C && grid[nr][nc] == 1) {
    
    
                                            // 0 <= nr && nr < R && 0 <= nc && nc < C,代指在grid有效范围之内,grid[nr][nc] == 1新鲜要处理
                        grid[nr][nc] = 2;
                        int ncode = nr * C + nc;
                        queue.add(ncode); // 入队
                        // 计次的关键 元素 grid[r][c] 的上左下右元素得腐烂时间应该一致
                        depth.put(ncode, depth.get(code) + 1);
                        ans = depth.get(ncode);
                    }
                }
            }
 
                          //检查grid,此时的grid能被感染已经都腐烂了,此时还新鲜的橘子无法被感染
            for (int[] row: grid)
                for (int v: row)
                    if (v == 1)
                        return -1;
            return ans;
}
    }

Guess you like

Origin blog.csdn.net/weixin_38370441/article/details/115249006