2025年- G27-Lc101-542. 01 矩阵--java版

发布于:2025-03-29 ⋅ 阅读:(26) ⋅ 点赞:(0)

1.题目描述

在这里插入图片描述

在这里插入图片描述

2.思路

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

总结:用广度优先搜索,首先要确定0的位置,不为0的位置,我们要更新的它的值,只能往上下左右寻找跟它最近的0的位置。
解题思路
我们用 BFS(广度优先搜索)求解,因为 BFS 可以保证最短路径。计算出每个 1 到最近的 0 的最短距离。

步骤:

初始化队列

先找到所有的 0,把它们的坐标 (i, j) 放入队列 queue,并初始化 dist[i][j] = 0。

其他的 1 先标记为 -1,表示未计算。

BFS 计算最短距离

每次从 queue 取出一个 (i, j) 位置的 0,尝试向 四个方向(上、下、左、右)扩展:

如果新位置是 -1(未计算),就更新它的 dist 值 = 当前值 +1,然后把它加入 queue 继续处理。

在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
BFS 遍历所有 1,把 -1 变成最短距离,直到 队列为空。⚡ 结束条件:

队列 queue 为空时,所有 1 都已经更新,算法结束。✅ 先把 0 入队,1 变 -1
✅ 从 0 开始 BFS,层层扩展
✅ BFS 遍历完所有 1,队列为空时结束

这样,最终矩阵每个 1 的值就是它到最近 0 的最短距离!
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
例子1:

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

个人总结:0值保持不变,1值赋值为-1.从0的位置出发,上下左右扫描,遇到-1,将距离更新为1并且赋值给当前遇到的元素。从当前元素(比如1)出发遇到值为-1的继续更新,并把此时距离2赋值给当前遇到的-1.以此类推,从当前元素(比如2)出发,遇到值为-1的值再次更新,并把此时距离=3赋值给遇到的-1.
在这里插入图片描述

例子2:

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

3.代码实现

方法一:

class Solution {
   
    public int[][] updateMatrix(int[][] mat) {
        int m = mat.length;//计算初始二维数组的行数
        int n = mat[0].length;//计算初始二维数组的列数
        int[][] dist = new int[m][n];
        //定义一个队列
        Queue<int[]> s1 = new LinkedList<>();
        //LinkedList<>(常用,支持 FIFO 队列)
        // 1. 初始化:找到所有 0,设定距离,1 设为 -1
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (mat[i][j] == 0) {
                    dist[i][j] = 0;
                    s1.offer(new int[]{i, j});
                    //new int[]{i, j} 这里是 一维数组,它的作用是将 (i, j) 这个坐标存入队列。
                } else {
                    dist[i][j] = -1;

                }
            }
        }

        // 2.方向数组(上、下、左、右)
        int[][] directions = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};

        // 2. BFS 遍历所有 1,更新最近 0 的距离
        while (!s1.isEmpty()) {
            //队列 queue 是 Queue<int[]>,即存储的是一维数组 int[],每个 int[] 代表一个坐标点 (x, y)。
            //queue.poll() 返回的是 queue 里存储的 int[] 数组,它的结构是 [x, y],即一个一维数组,包含两个整数(行号 x 和列号 y)。
            int[] curr = s1.poll();//存储当前坐标的一维数组,长度为 2 的一维数组。
            //for (int i = 0; i < directions.length; i++) {
            //    int dx = directions[i][0];
            //    int dy = directions[i][1];
            //
            //    int newX = x + dx;
            //    int newY = y + dy;
            //}

        for (int[] dir : directions) {
            // dir = {-1, 0},dir = {1, 0},{1,0},{-1,0}
            int newX = curr[0] + dir[0];
            int newY = curr[1] + dir[1];
            if (newX >= 0 && newX < m && newY >= 0 && newY < n && dist[newX][newY] == -1) {
                //dist[newX][newY]==-1,说明刚开始0的元素附近为1的元素把他们设置为-1,dist[newX][newY]为0附近的元素
                dist[newX][newY]=dist[curr[0]][curr[1]]+1;
                s1.offer(new int[]{newX,newY});
            }
        }

    }
    return dist;

        // 检查边界 & 是否未计算

    }
}

带测试方法:

import java.util.LinkedList;
import java.util.Queue;

public class test05 {
    public int[][] updateMatrix(int[][] mat) {
        int m = mat.length;//计算初始二维数组的行数
        int n = mat[0].length;//计算初始二维数组的列数
        int[][] dist = new int[m][n];
        //定义一个队列
        Queue<int[]> s1 = new LinkedList<>();
        //LinkedList<>(常用,支持 FIFO 队列)
        // 1. 初始化:找到所有 0,设定距离,1 设为 -1
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (mat[i][j] == 0) {
                    dist[i][j] = 0;
                    s1.offer(new int[]{i, j});
                    //new int[]{i, j} 这里是 一维数组,它的作用是将 (i, j) 这个坐标存入队列。
                } else {
                    dist[i][j] = -1;

                }
            }
        }

        // 2.方向数组(上、下、左、右)
        int[][] directions = {{0, -1}, {0, 1}, {1, 0}, {-1, 0}};

        // 2. BFS 遍历所有 1,更新最近 0 的距离
        while (!s1.isEmpty()) {
            //队列 queue 是 Queue<int[]>,即存储的是一维数组 int[],每个 int[] 代表一个坐标点 (x, y)。
            //queue.poll() 返回的是 queue 里存储的 int[] 数组,它的结构是 [x, y],即一个一维数组,包含两个整数(行号 x 和列号 y)。
            int[] curr = s1.poll();//存储当前坐标的一维数组,长度为 2 的一维数组。
            //for (int i = 0; i < directions.length; i++) {
            //    int dx = directions[i][0];
            //    int dy = directions[i][1];
            //
            //    int newX = x + dx;
            //    int newY = y + dy;
            //}

        for (int[] dir : directions) {
            // dir = {-1, 0},dir = {1, 0},{1,0},{-1,0}
            int newX = curr[0] + dir[0];
            int newY = curr[1] + dir[1];
            if (newX >= 0 && newX < m && newY >= 0 && newY < n && dist[newX][newY] == -1) {
                //dist[newX][newY]==-1,说明刚开始0的元素附近为1的元素把他们设置为-1,dist[newX][newY]为0附近的元素
                dist[newX][newY]=dist[curr[0]][curr[1]]+1;
                s1.offer(new int[]{newX,newY});
            }
        }

    }
    return dist;

        // 检查边界 & 是否未计算

    }
    public static void main(String[] args){
        test05 solution = new test05();
        int[][] mat={
            {0, 0, 0},
            {0, 1, 0},
            {1, 1, 1}
        };
        int[][] reasult= solution.updateMatrix(mat);
        for(int[] row:reasult)
        {
            for(int num:row)
            {
                System.out.print(num+" ");
            }
            System.out.println();

        }
    }


}

关键代码:

// 2. BFS 遍历
        while (!queue.isEmpty()) {
            int[] cell = queue.poll();
            int x = cell[0], y = cell[1];

            for (int[] dir : directions) {
                int newX = x + dir[0];
                int newY = y + dir[1];

                // 检查边界 & 是否未访问
                if (newX >= 0 && newX < m && newY >= 0 && newY < n && dist[newX][newY] == -1) {
                    dist[newX][newY] = dist[x][y] + 1; // 正确更新距离
                    queue.offer(new int[]{newX, newY}); // 加入队列
                }
            }
        }

补充队列的offer和poll用法
queue.offer()和queue.poll()的用法

import java.util.LinkedList;
import java.util.Queue;

public class QueueExample {
    public static void main(String[] args) {
        // 创建一个队列(FIFO:先进先出)
        Queue<Integer> queue = new LinkedList<>();

        // 向队列中添加元素
        queue.offer(10);
        queue.offer(20);
        queue.offer(30);

        System.out.println("队列内容:" + queue); // [10, 20, 30]

        // 取出队列头部元素(不删除)
        System.out.println("队头元素:" + queue.peek()); // 10

        // 取出并删除队列头部元素
        System.out.println("出队元素:" + queue.poll()); // 10

        System.out.println("队列内容:" + queue); // [20, 30]
    }
}

import java.util.PriorityQueue;
import java.util.Queue;

public class PriorityQueueExample {
    public static void main(String[] args) {
        Queue<Integer> pq = new PriorityQueue<>();

        // 添加元素
        pq.offer(30);
        pq.offer(10);
        pq.offer(20);

        System.out.println("队列内容:" + pq); // [10, 30, 20] (内部最小堆)

        // 取出最小的元素(自动排序)
        System.out.println("出队元素:" + pq.poll()); // 10
        System.out.println("出队元素:" + pq.poll()); // 20
        //queue.poll() 与 remove() 类似,但 remove() 队列为空时会抛异常。
    }
}