力扣做题记录——算法入门day9

力扣做题记录——算法入门day9

542.01矩阵

  给定一个由01组成的矩阵mat,请输出一个大小相同的矩阵,其中每一个格子是mat中对应位置元素到最近的0的距离。两个相邻元素间的距离为1
示例1
在这里插入图片描述

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

示例2
在这里插入图片描述

输入:mat = [[0,0,0],[0,1,0],[1,1,1]]
输出:[[0,0,0],[0,1,0],[1,2,1]]

提示

  • m == mat.length
  • n == mat[i].length
  • 1 <= m, n <= 10^4
  • 1 <= m * n <= 10^4
  • mat[i][j] is either 0 or 1
  • mat中至少有一个0

代码

\\ 方法1 两次遍历
vector<vector<int>> updateMatrix(vector<vector<int>>& mat) {
    int m = mat[0].size(), n = mat.size();
    vector<vector<int>> res(n,vector<int>(m,INT_MAX - 1));
    // 第一次从左上向右下遍历
    for (int i = 0; i < n; i++)
    {
        for (int j = 0; j < m; j++)
        // 如果当前mat元素为0,则其到0的最短距离为0
        if (mat[i][j] == 0) res[i][j] = 0;
        else
        {
        	// 如果当前mat元素为1,则取其及其上方单元格值加1的最小值
            if (j > 0)
            res[i][j] = min(res[i][j],res[i][j - 1] + 1);
            // 如果当前mat元素为1,则取其及其左方单元格值加1的最小值
            if (i > 0)
            res[i][j] = min(res[i][j],res[i - 1][j] + 1);
        }
    }
    // 第二次从右下向左上遍历
    for (int i = n - 1; i >= 0; i--)
    {
        for (int j = m - 1; j >= 0; j--)
        if (mat[i][j] == 0) res[i][j] = 0;
        else
        {
        	// 如果当前mat元素为1,则取其及其下方单元格值加1的最小值
            if (j < m - 1)
            res[i][j] = min(res[i][j],res[i][j + 1] + 1);
            // 如果当前mat元素为1,则取其及其右方单元格值加1的最小值
            if (i < n - 1)
            res[i][j] = min(res[i][j],res[i + 1][j] + 1);
        }
    }
    return res;

//  方法2 广度优先搜索
private:
    static constexpr int dirs[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}};

public:
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int m = matrix.size(), n = matrix[0].size();
        vector<vector<int>> dist(m, vector<int>(n));
        vector<vector<int>> seen(m, vector<int>(n));
        queue<pair<int, int>> q;
        // 将所有的 0 添加进初始队列中
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (matrix[i][j] == 0) {
                    q.emplace(i, j);
                    seen[i][j] = 1;
                }
            }
        }

        // 广度优先搜索
        while (!q.empty()) {
            auto [i, j] = q.front();
            q.pop();
            for (int d = 0; d < 4; ++d) {
                int ni = i + dirs[d][0];
                int nj = j + dirs[d][1];
                if (ni >= 0 && ni < m && nj >= 0 && nj < n && !seen[ni][nj]) {
                    dist[ni][nj] = dist[i][j] + 1;
                    q.emplace(ni, nj);
                    seen[ni][nj] = 1;
                }
            }
        }

        return dist;
    }
}

994.腐烂的橘子

  在给定的m x n网格grid中,每个单元格可以有以下三个值之一:

  • 0代表空单元格;
  • 1代表新鲜橘子;
  • 2代表腐烂的橘子。

  每分钟,腐烂的橘子 周围 4 个方向上相邻 的新鲜橘子都会腐烂。
  返回 直到单元格中没有新鲜橘子为止所必须经过的最小分钟数。如果不可能,返回 -1
示例1
在这里插入图片描述

输入:grid = [[2,1,1],[1,1,0],[0,1,1]]
输出:4

示例2

输入:grid = [[2,1,1],[0,1,1],[1,0,1]]
输出:-1
解释:左下角的橘子(第 2 行, 第 0 列)永远不会腐烂,因为腐烂只会发生在 4 个正向上。

示例3

输入:grid = [[0,2]]
输出:0
解释:因为 0 分钟时已经没有新鲜橘子了,所以答案就是 0 。

提示

  • m == grid.length
  • n == grid[i].length
  • 1 <= m, n <= 10
  • grid[i][j]仅为012

思路

  1. 创建一个队列,找到所有的腐烂橘子(数字2),将他们入队;
  2. 向每一个腐烂橘子的四周遍历,将新鲜橘子(数字1)传染(改为2),同时时间+1;
  3. 删除队列中的已经传染过别的橘子的腐烂橘子,将新被传染的橘子入队

几种情况

  1. 网格中没有新鲜橘子,直接返回0;
  2. 网格中有新鲜橘子,但没有腐烂橘子,直接返回-1;
  3. 类似示例2,有新鲜橘子不会被传染。这时要统计网格中的新鲜橘子个数,如果被传染的个数和新鲜的个数不同,说明有新鲜橘子没有被传染,要返回-1。

代码

const int dx[4] = {1,0,0,-1};
const int dy[4] = {0,1,-1,0};
int time[10][10]; // 传染到每个新鲜橘子的时间
int res; // 结果
int cnt = 0; // 当前新鲜橘子的个数
int orangesRotting(vector<vector<int>>& grid) {
    int m = grid.size(), n = grid[0].size();
    queue<pair<int,int>> record;
    // 统计腐烂橘子的位置和新鲜橘子的个数
    for (int i = 0; i < m; i++)
    {
        for (int j = 0; j < n; j++)
        {
            if (grid[i][j] == 2)
            record.push(make_pair(i,j));
            if (grid[i][j] == 1)
            cnt++;
        }
    }
    // 如果没有新鲜橘子,直接返回0
    if (!cnt)
    return 0;
    // 如果有新鲜橘子但没有腐烂橘子,直接返回-1
    if (record.empty())
    return -1;
    // 广度优先遍历
    while (!record.empty())
    {
    	// 取出队头的腐烂橘子
        pair<int,int> point = record.front();
        record.pop();
        // 腐烂橘子向四周传染
        for (int i = 0; i < 4; i++)
        {
            int x = point.first + dx[i];
            int y = point.second + dy[i];
            // 如果超出了网格范围,就直接向下个方向传染
            if (x < 0 || x >= m || y < 0 || y >= n)
            {continue;}
            // 如果腐烂橘子的周围有新鲜橘子
            if (grid[x][y] == 1)
            {
            	// 将新鲜橘子传染
                grid[x][y] = 2;
                // 传染时间是上个腐烂橘子传染时间+1
                time[x][y] = time[point.first][point.second] + 1;
                // 记录当前的总时间
                res = time[x][y];
                // 把新被传染的橘子入队
                record.push(make_pair(x,y));
                // 新鲜橘子的个数-1
                cnt--;
            }
        }

    }
    // 如果最后没有新鲜橘子了,就输出总时间,如果有新鲜橘子剩下,就返回-1
    return cnt?-1:res;
}

  本文题目及部分解答来自力扣:

https://leetcode-cn.com/problems/rotting-oranges/
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值