广度优先搜索(BFS)

广度优先搜索(BFS)

  • BFS介绍
  • BFS解决哪些问题
  • BFS模板
    • leetcode 994 腐烂的橘子
    • leetcode111求二叉树的最小深度
    • 迷宫问题

BFS介绍

BFS是最简便的图的搜索算法之一,dijkstra单元最短路径算法和prime最小生成树算法都采用了和广度优先搜索类似的算法,
属于一种盲目算法,目的是系统地展开并检查图中所有节点,以寻找结果,和DFS的区别,dfs是一条路走到黑,如果没有路就返回,BFS是从上往下依次遍历,一般用队列来实现BFS

广度优先搜索(BFS)_第1张图片

BFS解决哪些问题

1.最短路径问题 通过bfs找到两个节点之间的最短路径
2.迷宫问题 可以用bfs来搜索迷宫中的最短路径,起点到终点
3.层级遍历 bfs可以按层级遍历树或图的节点,逐层处理
4.图的连通性 bfs可以用于确定两个节点之间是否存在路径或者图中的联通组件
5 单词变换问题

BFS模板

// 计算从起点 start 到终点 target 的最近距离
int BFS(Node start, Node target) {
    Queue<Node> q; // 核心数据结构
    Set<Node> visited; // 避免走回头路
    
    q.offer(start); // 将起点加入队列
    visited.add(start);

    while (q not empty) {
        int sz = q.size();
        /* 将当前队列中的所有节点向四周扩散 */
        for (int i = 0; i < sz; i++) {
            Node cur = q.poll();
            /* 划重点:这里判断是否到达终点 */
            if (cur is target)
                return step;
            /* 将 cur 的相邻节点加入队列 */
            for (Node x : cur.adj()) {
                if (x not in visited) {
                    q.offer(x);
                    visited.add(x);
                }
            }
        }
    }
    // 如果走到这里,说明在图中没有找到目标节点
}

leetcode 994 腐烂的橘子

思路 一眼就是bfs进行暴力搜索,将烂橘子的四周全部变成烂橘子,然后不断的网下,刚开始先搜索一下整张图,找出正常橘子的数目,将烂橘子添加到队列中去,当烂橘子感染周围橘子的时候,直接添加到队列中去。

import java.time.Year;
import java.util.Deque;
import java.util.LinkedList;
import java.util.Queue;

//leetcode submit region begin(Prohibit modification and deletion)
class Solution {
    public int orangesRotting(int[][] grid) {

        //分析,一眼bfs,广度优先搜索,找到一个烂的橘子,让他的四周都变成烂橘子
        int m=grid.length;
        int n=grid[0].length;
        int count=0; //记录橘子的数量
        Queue<int []> queue=new LinkedList<>(); //定义队列
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j]==2){
                    queue.offer(new int[]{i,j}); //将当前的坐标加进来
                } else if (grid[i][j]==1) {
                    count++;
                }
            }
        }
        int time=0;
        //先把图遍历一遍
        if (count==0){
            return 0;
        }
        while (!queue.isEmpty()){
            if (count==0){
                return time;
            }
            int size= queue.size();
            for (int i = 0; i < size; i++) {
                int [] orange=queue.poll(); //出队列
                int x=orange[0];
                int y=orange[1]; //烂橘子的坐标
                if (x-1>=0&&grid[x-1][y]==1){
                    grid[x-1][y]=2;//变为烂橘子
                    count--;
                    queue.offer(new int[]{x-1, y});
                }
                if (x+1<m&&grid[x+1][y]==1){
                    grid[x+1][y]=2;//变为烂橘子
                    count--;
                    queue.offer(new int[]{x+1, y});
                }
                if (y-1>=0&&grid[x][y-1]==1){
                    grid[x][y-1]=2;//变为烂橘子
                    count--;
                    queue.offer(new int[]{x, y-1});
                }
                if (y+1<n&&grid[x][y+1]==1){
                    grid[x][y+1]=2;//变为烂橘子
                    count--;
                    queue.offer(new int[]{x, y+1});
                }
            }

          time++; //每感染一次时间都会++;

        }
        return -1;

    }

}
//leetcode submit region end(Prohibit modification and deletion)

leetcode111求二叉树的最小深度

可以用bfs求解,一层一层的去遍历,用队列去模拟,如果一共节点的左孩子和右孩子都为null,返回这一层所在的深度,就是二叉树的最小深度。
如果左右孩子不等于null,就将左右孩子都添加到队列中来。

class Solution {
    int minDepth(TreeNode root) {
        if (root==null){
            return 0;
        }
    //dfs 广度优先搜索
        Queue<TreeNode> queue =new LinkedList<>();
        queue.offer(root); //将根节点添加进来
        int depth=1; //原始的深度
        //用队列来模拟功能
        while (!queue.isEmpty()){
            int size=queue.size();
            for (int i = 0; i <size ; i++) {
                TreeNode cur = queue.poll();
                if (cur.left==null&&cur.right==null){
                    //左右都为null,说明了是根节点了
                    return depth;
                }
                if (cur.left!=null){
                    queue.offer(cur.left);
                }
                if (cur.right!=null){
                    queue.offer(cur.right);
                }
            }
            depth++;
        }
        return depth;
    }

}

迷宫问题

蓝桥杯2019省赛迷宫问题

迷宫的入口在左上角,出口在左下角,在迷宫中只能从一个位置到另一个位置,DULR代表方向,向上,向下,向左,向右走;
可以
思路 定义一共静态的内部类,变量有x坐标,y坐标,走的步数,走的步在这里插入代码片数对应的字符

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.io.PrintWriter;
import java.util.LinkedList;
import java.util.Queue;

public class 迷宫2 {
    static int num;
    static int xsize = 30;
    static int ysize = 50;
    static char[][] arr = new char[xsize][ysize];
    static boolean[][] help = new boolean[xsize][ysize];
    static int[][] dir = {{1, 0}, {0, -1}, {0, 1}, {-1, 0}};
    static char[] sign = {'D', 'L', 'R', 'U'};

    // 定义节点类 Node
    public static class Node {
        int x; // 节点的 x 坐标
        int y; // 节点的 y 坐标
        String num; // 节点的值
        int runnum; // 节点的运行值

        // 构造函数,用于初始化节点对象
        public Node(int x, int y, String num, int runnum) {
            this.x = x;
            this.y = y;
            this.num = num;
            this.runnum = runnum;
        }
    }

    public static void main(String[] args) throws IOException {
        BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
        PrintWriter out = new PrintWriter(new OutputStreamWriter(System.out));

        // 读取迷宫数据到二维数组 arr
        for (int i = 0; i < xsize; i++) {
            arr[i] = in.readLine().toCharArray();
        }

        // 调用 bfs() 方法执行广度优先搜索
        out.println(bfs());
        out.print(num);
        out.flush();
    }

    // 广度优先搜索方法
    static String bfs() {
        Queue<Node> list = new LinkedList<>();
        int x = 0;
        int y = 0;
        int runnum = 0;
        list.add(new Node(x, y, "", runnum));

        while (!list.isEmpty()) {
            Node now = list.poll();
            help[now.x][now.y] = true;

            // 遍历四个方向进行移动
            for (int i = 0; i < 4; i++) {
                int xx = now.x + dir[i][0];
                int yy = now.y + dir[i][1];

                // 检查下一个位置是否合法
                if (check(xx, yy) && !help[xx][yy] && arr[xx][yy] == '0') {
                    list.add(new Node(xx, yy, now.num + sign[i], now.runnum + 1));

                    // 判断是否到达终点
                    if (xx == xsize - 1 && yy == ysize - 1) {
                        num = now.runnum + 1;
                        return now.num + sign[i];
                    }
                }
            }
        }

        return "";
    }

    // 辅助方法,检查坐标是否在合法范围内
    private static boolean check(int xx, int yy) {
        return xx >= 0 && yy >= 0 && xx < xsize && yy < ysize;
    }
}

你可能感兴趣的:(宽度优先,算法)