难度中等158
给定一个由 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。
- 矩阵中的元素只在四个方向上相邻: 上、下、左、右
思路一: 这道题属于 边长为1 的最短路径问题 ,从每个 0出发,考虑 0 到 1 的距离,从 0 出现的位置 进行BFS(需要对每个位置 0 都进行这样的操作,),这样明显超时!!!!
这里有个小优化的思路:利用Dijkstra的思想!!!
把所有的 0 的压进队列,然后选择队列外的点,如果距离比之前的小 ,就更新,进栈,直至距离不再更新 也不会入栈
先放一下TLE代码
class Solution {
public:
struct node{
int x,y;
int floor;
};
int m,n;
bool Judge(int x,int y){
if(x>=0&&x<m&&y>=0&&y<n){
return true;
}
return false;
}
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
m = matrix.size();
n = matrix[0].size();
vector<vector<int>> ans(m,vector<int>(n,0x3f3f3f3f));
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
if(matrix[i][j]==0){//进行BFS
vector<vector<bool>> flag(m,vector<bool>(n,0)); //一开始都是 0没有访问
queue<node> q;
ans[i][j] = 0; // 是0 的话置 0
node tmp;
tmp.x = i;
tmp.y = j;
tmp.floor = 0;
// cout<<"i "<<i<<" j "<<j<<endl;
q.push(tmp);
flag[i][j] = 1;
while(!q.empty()){
node now = q.front();
q.pop();
for(int i=0;i<4;i++){
int tmpx = now.x+dir[i][0];
int tmpy = now.y+dir[i][1];
if(Judge(tmpx,tmpy)&&matrix[tmpx][tmpy]==1&&flag[tmpx][tmpy]==0){
tmp.x = tmpx;
tmp.y = tmpy;
tmp.floor = now.floor+1;
flag[tmpx][tmpy] = 1;
// cout<<" tmp.x "<< tmp.x<<"tmp.y "<<tmp.y<<"tmp.floor "<<tmp.floor<<endl;
q.push(tmp);
if(tmp.floor<ans[tmpx][tmpy])
ans[tmpx][tmpy] = tmp.floor;
}
}
}
}
}
return ans;
}
};
Ac代码
class Solution {
public:
struct node{
int x,y;
int floor;
};
bool Judge(int x,int y){
if(x>=0&&x<m&&y>=0&&y<n){
return true;
}
return false;
}
int m,n;
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
m = matrix.size();
n = matrix[0].size();
vector<vector<int>> ans(m,vector<int>(n,0x3f3f3f3f));
int dir[4][2]={{1,0},{0,1},{-1,0},{0,-1}};
queue<node> q;
node tmp;
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
if(matrix[i][j]==0){
tmp.x = i;
tmp.y = j;
tmp.floor = 0;
ans[i][j] = 0;
q.push(tmp);
}
}
while(!q.empty()){
node now = q.front();
q.pop();
for(int i=0;i<4;i++){
int tmpx = now.x+dir[i][0];
int tmpy = now.y+dir[i][1];
if(Judge(tmpx,tmpy)&&matrix[tmpx][tmpy]==1){
tmp.x = tmpx;
tmp.y = tmpy;
tmp.floor = now.floor+1;
if(ans[tmpx][tmpy]>tmp.floor){
q.push(tmp);
ans[tmpx][tmpy]=tmp.floor;
}
}
}
}
return ans;
}
};
动态规划思路: (我觉得这个解释很 玄学!!!!)
对于一个节点来说,它到 0 的距离可以通过邻居的最近距离计算,在这种情况下最近距离是邻居的距离 + 1。因此,这就让我们想到了动态规划!
对于每个 1,到 0 的最短路径可能从任意方向。所以我们需要检查所有 4 个方向。在从上到下的迭代中,我们需要检查左边和上方的最短路径;我们还需要另一个从下往上的循环,检查右边和下方的方向。
算法
从上至下、从左至右迭代整个矩阵:
更新
\text{dist}[i][j]=\min(\text{dist}[i][j],\min(\text{dist}[i][j-1],\text{dist}[i-1][j])+1)dist[i][j]=min(dist[i][j],min(dist[i][j−1],dist[i−1][j])+1)
最近距离考虑上方邻居和左侧邻居距离 + 1,这在前面的迭代中已经计算完成。
从下到上、从右至左迭代整个矩阵:
更新
\text{dist}[i][j]=\min(\text{dist}[i][j],\min(\text{dist}[i][j+1],\text{dist}[i+1][j])+1)dist[i][j]=min(dist[i][j],min(dist[i][j+1],dist[i+1][j])+1)
最近距离考虑下方邻居和右侧邻居距离 + 1,这在前面的迭代中已经计算完成。
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
int m = matrix.size();
int n = matrix[0].size();
vector<vector<int> > dp(m,vector<int>(n,0x3f3f3f3f));
for(int i=0;i<m;i++)
for(int j=0;j<n;j++){
if(matrix[i][j]==0){
dp[i][j] = 0;
continue;
}
else{
if(i>0)
dp[i][j] = min(dp[i][j],dp[i-1][j]+1);
if(j>0)
dp[i][j] = min(dp[i][j],dp[i][j-1]+1);
}
}
for(int i=m-1;i>=0;i--)
for(int j=n-1;j>=0;j--){
if(matrix[i][j]==0){
dp[i][j] = 0;
continue;
}
else{
if(i<m-1)
dp[i][j] = min(dp[i][j],dp[i+1][j]+1);
if(j<n-1)
dp[i][j] = min(dp[i][j],dp[i][j+1]+1);
}
}
return dp;
}
};