图论(bfs系列)9/30

单源点系列:

一、二进制矩阵中的最短路径

给你一个 n x n 的二进制矩阵 grid 中,返回矩阵中最短 畅通路径 的长度。如果不存在这样的路径,返回 -1 。

二进制矩阵中的 畅通路径 是一条从 左上角 单元格(即,(0, 0))到 右下角 单元格(即,(n - 1, n - 1))的路径,该路径同时满足下述要求:

  • 路径途经的所有单元格的值都是 0 。
  • 路径中所有相邻的单元格应当在 8 个方向之一 上连通(即,相邻两单元之间彼此不同且共享一条边或者一个角)。
思路:

由题意可得,bfs是从(0,0)出发(单源点),然后找到一条最短畅通路径的长度。

1.首先我们要判断起点和终点的值是否都是0,如果不是直接返回-1;

2.然后判断矩阵的规格,如果是1*1的矩阵,直接返回1;

3.然后开始bfs搜索,每次我们可以朝着八个方向走出一步,所以定义一个方向数组。

int[][] directions={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};

4.然后套用dfs的模板即可。

        while(!queue.isEmpty()){
            int size=queue.size();
            for(int i=0;i<size;i++){
                int[] next=queue.poll();//循环遍历这一层的元素
                for(int[] direc:directions){
                    int newX=next[0]+direc[0];
                    int newY=next[1]+direc[1];
                    if(newX>=0&&newX<m&&newY>=0&&newY<n&&!visited[newX][newY]&&grid[newX][newY]==0){
                        if(newX==m-1&&newY==n-1)return step+1;
                        visited[newX][newY]=true;
                        queue.add(new int[]{newX,newY});
                    }
                }
            }
            step++;          
        }

 

代码:
class Solution {
    boolean[][] visited;
    int m;
    int n;
    int[][] directions={{-1,-1},{-1,0},{-1,1},{0,-1},{0,1},{1,-1},{1,0},{1,1}};
    public int shortestPathBinaryMatrix(int[][] grid) {
        if(grid[0][0]!=0||grid[grid.length-1][grid[0].length-1]!=0)return -1;
        m=grid.length;
        n=grid[0].length;
        if(m == 1 && n == 1 && grid[0][0] == 0) return 1;
        visited=new boolean[m][n];
        Queue<int[]> queue=new ArrayDeque<int[]>();
        queue.add(new int[]{0,0});
        visited[0][0]=true;
        int step=1;

        while(!queue.isEmpty()){
            int size=queue.size();
            for(int i=0;i<size;i++){
                int[] next=queue.poll();//循环遍历这一层的元素
                for(int[] direc:directions){
                    int newX=next[0]+direc[0];
                    int newY=next[1]+direc[1];
                    if(newX>=0&&newX<m&&newY>=0&&newY<n&&!visited[newX][newY]&&grid[newX][newY]==0){
                        if(newX==m-1&&newY==n-1)return step+1;
                        visited[newX][newY]=true;
                        queue.add(new int[]{newX,newY});
                    }
                }
            }
            step++;          
        }
        return -1;
    }
}

二、迷宫中离入口最近的出口

给你一个 m x n 的迷宫矩阵 maze (下标从 0 开始),矩阵中有空格子(用 '.' 表示)和墙(用 '+' 表示)。1.同时给你迷宫的入口 entrance ,用 entrance = [entrancerow, entrancecol] 表示你一开始所在格子的行和列。

每一步操作,2.你可以往 上,下,左 或者 右 移动一个格子。你不能进入墙所在的格子,你也不能离开迷宫。3.你的目标是找到离 entrance 最近 的出口出口 的含义是 maze 边界 上的 空格子entrance 格子 不算 出口。

请你返回从 entrance 到最近出口的最短路径的 步数 ,如果不存在这样的路径,请你返回 -1 。

思路:

1.首先,这是一个单源点的bfs搜索题,for循环不断遍历每一次搜索能到达的点,然后把这些点加入queue队列中。

2.然后再次for循环遍历这些队列,到达出口的判定条件是:在第一行或者最后一行 第一列或者最后一列。

代码:
class Solution {
    int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };

    public int nearestExit(char[][] maze, int[] entrance) {
        int m = maze.length;
        int n = maze[0].length;
        boolean[][] visited = new boolean[m][n];
        Queue<int[]> queue = new ArrayDeque<int[]>();
        queue.add(entrance);
        visited[entrance[0]][entrance[1]] = true;
        int steps = 0;

        while (!queue.isEmpty()) {
            int size=queue.size();
            for (int i = 0; i < size; i++) {
                int[] current = queue.poll();
                for (int[] dir : directions) {
                    int newX = current[0] + dir[0];
                    int newY = current[1] + dir[1];
                    if (newX >= 0 && newX < m && newY >= 0 && newY < n && !visited[newX][newY] && maze[newX][newY] == '.') {
                        if (newX == 0 || newX == m - 1 || newY == 0 || newY == n - 1)
                            return steps+1;
                        visited[newX][newY] = true;
                        queue.add(new int[] { newX, newY });
                    }
                }
            }
            steps++;
        }
        return -1;
    }
}

多源点系列:

三、地图分析

你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地。

请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,并返回该距离。如果网格上只有陆地或者海洋,请返回 -1

我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1| 。

思路:

要求0到最近的1的距离的最大值。我们可以计算1到最近的0的距离的最大值。

多源点问题:

1.首先我们将所有值为1的点都加入到队列中,然后将值为0的点的值都改为-1;(这样就不用使用visited数组来记忆化了)

2.然后对队列循环,当遇到-1的时候,我们将它标记一下。然后继续寻找。最后返回step-1

(为什么是step-1呢,因为在最后一次查找的时候,已经无法再向外层扩展了,但还是++,所以最后返回的时候应该再减去1)

代码:
class Solution {
    int[][] directions = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } };
    int[][] grid;
    int m;
    int n;

    public int maxDistance(int[][] grid) {
        this.grid = grid;
        m = grid.length;
        n = grid[0].length;
        Queue<int[]> queue = new ArrayDeque<int[]>();
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (grid[i][j] == 1) {
                    queue.add(new int[] { i, j });
                }else{
                    grid[i][j]=-1;
                }
            }
        }
        if(queue.size()==0||queue.size()==n*n)return -1;
        int step=0;
        while (!queue.isEmpty()) {
            int size = queue.size();
            for (int i = 0; i < size; i++) {
                int[] current = queue.poll();
                for (int[] dirc : directions) {
                    int newX = current[0] + dirc[0];
                    int newY = current[1] + dirc[1];
                    if (newX >= 0 && newX < m && newY >= 0 && newY < n &&grid[newX][newY]==-1) {
                        grid[newX][newY]=step+1;
                        queue.add(new int[] { newX, newY });
                    }
                }
            }
            step++;
        }
        return step-1;
    }
}

四、01矩阵

给定一个由 0 和 1 组成的矩阵 mat ,请输出一个大小相同的矩阵,其中每一个格子是 mat 中对应位置元素到最近的 0 的距离。

两个相邻元素间的距离为 1 。

示例 1:

输入:mat = [[0,0,0],[0,1,0],[0,0,0]]
输出:[[0,0,0],[0,1,0],[0,0,0]]
思路:

题目中要求每一个格子距离0的最小值。我们还是逆向思维,以1为主,找距离最小的0。

多源点问题:1.首先将所有的值为1的点都加入队列中,然后将值为0的点赋值为不能达到的值

2.然后套用模板,开始遍历队列。如果遇到值==-1的点,那我们就将这个格子的值赋为step;

3.最后返回格子即可。(我们在格子上原地修改)

代码:
class Solution {
    public int[][] updateMatrix(int[][] mat) {
        int[][] directions={{0,-1},{0,1},{-1,0},{1,0}};
        int m=mat.length;
        int n=mat[0].length;
        boolean[][] visited=new boolean[m][n];
        Queue<int[]> queue=new ArrayDeque<int[]>();
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(mat[i][j]==0)queue.add(new int[]{i,j});
                else mat[i][j]=-1;//先将值为1的位置赋为-1
            }
        }
        int step=1;
        while(!queue.isEmpty()){
            int size=queue.size();
            for(int i=0;i<size;i++){
                int[] current=queue.poll();
                for(int[] dirc:directions){
                    int newX=current[0]+dirc[0];
                    int newY=current[1]+dirc[1];
                    if(newX>=0&&newX<m&&newY>=0&&newY<n&&!visited[newX][newY]&&mat[newX][newY]==-1){
                        mat[newX][newY]=step;
                        queue.add(new int[]{newX,newY});       
                    }
                }
            }
            step++;
        }
        return mat;
    }
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值