Preguntas sobre el pincel LeetCode: BFS

guía

Explique la
comparación entre BFS y DFS

Palabras clave DFS: recursividad / pila + todas las soluciones La
implementación de DFS depende en gran medida de pila / recursividad, y simplemente resuelve el problema de cómo atravesar todos los elementos y buscar el "punto final".
Sin embargo, aunque DFS puede encontrar la ruta de llegada, no puede encontrar la ruta más corta.Para resolver este problema, se proporciona un algoritmo BFS (amplitud de primer recorrido).
Y la diferencia de DFS es que ya no se trata de cada bifurcación en la carretera una por una, sino que mientras se recorre hasta encontrar el final, correspondiente a las "capas" es el número de pasos necesarios para el camino más corto hacia
la solución anterior. Entre ellos, si necesita procesar todos los elementos en la cola actual (es decir, cuando necesita un concepto jerárquico), debe agregar un bucle for (i <tamaño).
Si solo procesa un elemento en la cola en un tiempo (sin concepto jerárquico), no es necesario agregar para el ciclo

Solución universal BFS

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
}

ejemplo

102. Cruce a nivel de árbol: solución estándar

Inserte la descripción de la imagen aquí

Referencia:
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是传入进来的参数,防止堆污染
            }
        }
    }
}

versión zigzag: deque
Inserte la descripción de la imagen aquí

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. Plan de estudios: clasificación topológica

Inserte la descripción de la imagen aquí
https://leetcode-cn.com/problems/course-schedule/
Clasificación topológica:
Respuesta:
https://leetcode-cn.com/problems/course-schedule/solution/ke-cheng-biao-by-leetcode-solution /
Artículo de referencia: La estructura de almacenamiento de gráficos y la realización de clasificación topológica
https://www.jianshu.com/p/cd24cfb6c8d0

Respuesta de la versión DFS:

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; // 当前处理完成:这里不再是清理标记而是替换为另一种状态
    }

Respuesta de la versión BFS;

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. Naranjas podridas: múltiples BFS

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

Primera búsqueda de amplitud de múltiples fuentes

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;
}
    }

Supongo que te gusta

Origin blog.csdn.net/weixin_38370441/article/details/115249006
Recomendado
Clasificación