【leet-code】542. 01 矩阵

题目描述

给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离。

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

示例 1:

输入:
0 0 0
0 1 0
0 0 0

输出:
0 0 0
0 1 0
0 0 0

示例 2:

输入:
0 0 0
0 1 0
1 1 1

输出:
0 0 0
0 1 0
1 2 1

注意:

  1. 给定矩阵的元素个数不超过 10000。
  2. 给定矩阵中至少有一个元素是 0。
  3. 矩阵中的元素只在四个方向上相邻: 上、下、左、右。

算法

可以用动态规划或者BFS,如果用DFS有超时的风险。

BFS

  1. 遍历matrix矩阵,将所有\(matrix[i][j]=0\)的位置信息\((i, j)\)保存到队列中,所有\(matrix[i][j]=1\)的将值从1改到定义的无穷大。
  2. 当队列不为空的时候,持续循环:
    • 从队列中弹出一个元素,获取位置信息,将该位置(i,j)的上下左右做个判断,如果某个位置上的值大于matrix[i][j]+1,那么将该值改为matrix[i][j]+1,重新压入队列
    • 进行改值操作的时候注意边界条件

BFS代码

#define INF 10000

class Solution {
    vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        int row = matrix.size();
        if (row == 0)
            return matrix;
        int col = matrix[0].size();

        queue<pair<int, int> > myQueue;
        for (int i = 0; i < row; i++)
        {
            for (int j = 0; j < col; j++)
            {
                if (matrix[i][j] == 0)
                    myQueue.push(pair<int, int>(i, j));
                else
                    matrix[i][j] = INF;
            }
        }

        while (!myQueue.empty())
        {
            pair<int, int> rec = myQueue.front();
            myQueue.pop();

            if (rec.first-1 >= 0 && matrix[rec.first-1][rec.second] > matrix[rec.first][rec.second]+1)
            {
                matrix[rec.first-1][rec.second] = matrix[rec.first][rec.second]+1;
                myQueue.push(pair<int, int>(rec.first-1, rec.second));
            }

            if (rec.second-1 >= 0 && matrix[rec.first][rec.second-1] > matrix[rec.first][rec.second]+1)
            {
                matrix[rec.first][rec.second-1] = matrix[rec.first][rec.second]+1;
                myQueue.push(pair<int, int>(rec.first, rec.second-1));
            }

            if (rec.first+1 < row && matrix[rec.first+1][rec.second] > matrix[rec.first][rec.second]+1)
            {
                matrix[rec.first+1][rec.second] = matrix[rec.first][rec.second]+1;
                myQueue.push(pair<int, int>(rec.first+1, rec.second));
            }

            if (rec.second+1 < col && matrix[rec.first][rec.second+1] > matrix[rec.first][rec.second]+1)
            {
                matrix[rec.first][rec.second+1] = matrix[rec.first][rec.second]+1;
                myQueue.push(pair<int, int>(rec.first, rec.second+1));
            }
        }
        return matrix;
    }

动态规划

基本的思想就是遍历matrix,如果matrix[i][j]是0的话,dp[i][j]直接为0,否则,它与四周的dp值有关,又因为从左上到右下的更新过程中,只能确定左上角两边的dp值;
所以要再从右下角往左上角遍历,这样就把dp[i][j]四周的dp值都考虑进去了。

动态规划代码

class Solution {
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
        // 两次遍历,左上到右下和右下到左上,更新完的dp就是最终的答案
        int row = matrix.size();
        if (row == 0)
            return matrix;
        int col = matrix[0].size();
        vector<vector<int> > dp(row, vector<int>(col));

        if (matrix[0][0] == 0)
            dp[0][0] = 0;
        else
            dp[0][0] = INF;

        // 第一次
        for (int i = 1; i < col; i++)
        {
            if (matrix[0][i] == 0)
                dp[0][i] = 0;
            else
                dp[0][i] = min(INF, dp[0][i-1] + 1);
        }

        for (int i = 1; i < row; i++)
        {
            if (matrix[i][0] == 0)
                dp[i][0] = 0;
            else
                dp[i][0] = min(INF, dp[i-1][0] + 1);
        }

        for (int i = 1; i < row; i++)
        {
            for (int j = 1; j < col; ++j)
            {
                if (matrix[i][j] == 0)
                    dp[i][j] = 0;
                else
                    dp[i][j] = min(INF, min(dp[i-1][j], dp[i][j-1]) + 1);
            }
        }

        // 打印第一次更新成果
//        for (int i = 0; i < row; i++)
//        {
//            for (int j = 0; j < col; j++)
//                cout << dp[i][j] << ' ';
//            cout << endl;
//        }
//
//        cout << "===========我是分割线===========" << endl;

        // 第二次
        for (int i = col - 2; i >= 0; i--)
        {
            if (matrix[row-1][i] == 0)
                dp[row-1][i] = 0;
            else
                dp[row-1][i] = min(dp[row-1][i], dp[row-1][i+1] + 1);
        }

        for (int i = row - 2; i >= 0; i--)
        {
            if (matrix[i][col-1] == 0)
                dp[i][col-1] = 0;
            else
                dp[i][col-1] = min(dp[i][col-1], dp[i+1][col-1] + 1);
        }

        for (int i = row - 2; i >= 0; i--)
        {
            for (int j = col - 2; j >= 0; j--)
            {
                if (matrix[i][j] == 1)
                    dp[i][j] = min(dp[i][j], min(dp[i+1][j], dp[i][j+1]) + 1);
            }
        }
        return dp;
    }
};
posted @ 2019-03-15 13:20  小王点点  阅读(543)  评论(0编辑  收藏  举报