给定一个由 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
注意:
- 给定矩阵的元素个数不超过 10000。
- 给定矩阵中至少有一个元素是 0。
- 矩阵中的元素只在四个方向上相邻: 上、下、左、右。
解法一:bfs
将所有的0都加入队列,1全部改为-1,这个为了防止和后面冲突,后面所有整数表示到0的最近的距离。
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int m=matrix.size(),n=matrix[0].size();
queue<pair<int,int>> q;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
if(!matrix[i][j])q.push(make_pair(i,j));
else matrix[i][j]=-1;
}
while(!q.empty()){
pair<int,int> t=q.front();q.pop();
int x=t.first,y=t.second;
int dir[4][2]={{-1,0},{1,0},{0,1},{0,-1}};
for(int i=0;i<4;i++){
int nx=x+dir[i][0];
int ny=y+dir[i][1];
if(nx>=0&&nx<m&&ny>=0&&ny<n&&matrix[nx][ny]==-1){
matrix[nx][ny]=matrix[x][y]+1;
q.push(make_pair(nx,ny));
}
}
}
return matrix;
}
};
看来对bfs的领悟还是不够透彻,最基本的bfs是二叉树的层序遍历,这种bfs最简单,从上而下,不用考虑会不会遇到调用同一个节点的问题;进阶一点的就是图的bfs,这需要解决上面提到的问题,目前最常用的解决方法就是数字值限制,只允许某个特定的值,调用后改为另一个值。这样访问循序就变成了二叉树一样的从上到下的单射。还有一种方法就是设置访问数组(少)
解法二:dp
这题的dp办法其实是最最简洁的。对于每个点,值为0距离为0,值不为0,则值为上下左右点最小的那个加1,我第一遍写的时候其实想到了这个方法,但是不知道没有计算出来的点如何处理。查资料后发现可以用两遍扫描法解决问题。
第一遍扫描左边和上面的点,取最小值加1
第二遍倒过来从右下角开始扫描,取右边和下面点的最小值加1
易错点:初始化为INT_MAX
分析:假如一个3*3的矩阵,只有右下角为0,其余为1。在第一遍扫描的过程中,[1,1]点左上都是INT_MAX,加1的过程会溢出,所以初始化为INT_MAX-1,不用担心溢出,取最小值永远也达不到INT_MAX
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int m=matrix.size(),n=matrix[0].size();
vector<vector<int>> res=matrix;
for(int i=0;i<m;i++)for(int j=0;j<n;j++)if(res[i][j])res[i][j]=INT_MAX-1;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
if(res[i][j]){
if(i>0)res[i][j]=min(res[i][j],res[i-1][j]+1);
if(j>0)res[i][j]=min(res[i][j],res[i][j-1]+1);
}
}
for(int i=m-1;i>=0;i--)
for(int j=n-1;j>=0;j--){
if(res[i][j]){
if(i<m-1)res[i][j]=min(res[i][j],res[i+1][j]+1);
if(j<n-1)res[i][j]=min(res[i][j],res[i][j+1]+1);
}
}
return res;
}
};