Given a matrix consists of 0 and 1, find the distance of the nearest 0 for each cell.
The distance between two adjacent cells is 1. Example 1:
Input:
0 0 0 0 1 0 0 0 0Output:
0 0 0 0 1 0 0 0 0
Example 2:
Input:
0 0 0 0 1 0 1 1 1Output:
0 0 0 0 1 0 1 2 1
Note:
- The number of elements of the given matrix will not exceed 10,000.
- There are at least one 0 in the given matrix.
- The cells are adjacent in only four directions: up, down, left and right.
Approach #1 Brute force [Time Limit Exceeded]
Intuition
Do what the question says.
Algorithm
- Initialize
dist[i][j]=INT_MAX
for all{i,j}
cells. - Iterate over the matrix.
- If cell is
0
,dist[i][j]=0
, - Else, for each
1
cell,- Iterate over the entire matrix
- If the cell is
0
, calculate its distance from current cell asabs(k-i)+abs(l-j)
. - If the distance is smaller than the current distance, update it.
C++
vector<vector<int> > updateMatrix(vector<vector<int> >& matrix) { int rows = matrix.size(); if (rows == 0) return matrix; int cols = matrix[0].size(); vector<vector<int> > dist(rows, vector<int>(cols, INT_MAX)); for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (matrix[i][j] == 0) dist[i][j] = 0; else { for (int k = 0; k < rows; k++) for (int l = 0; l < cols; l++) if (matrix[k][l] == 0) { int dist_01 = abs(k - i) + abs(l - j); dist[i][j] = min(dist[i][j], abs(k - i) + abs(l - j)); } } } } return dist; }
Complexity Analysis
-
Time complexity: O((r⋅c)2). Iterating over the entire matrix for each
1
in the matrix. -
Space complexity: O(r⋅c). No extra space required than the
vector<vector<int> > dist
Approach #2 Using BFS [Accepted]
Intuition
A better brute force: Looking over the entire matrix appears wasteful and hence, we can use Breadth First Search(BFS) to limit the search to the nearest 0
found for each 1
. As soon as a 0
appears during the BFS, we know that the 0
is nearest, and hence, we move to the next 1
.
Think again: But, in this approach, we will only be able to update the distance of one 1
using one BFS, which could in fact, result in slightly higher complexity than the Approach #1 brute force. But hey,this could be optimised if we start the BFS from 0
s and thereby, updating the distances of all the 1
s in the path.
Algorithm
- For our BFS routine, we keep a queue,
q
to maintain the queue of cells to be examined next. - We start by adding all the cells with
0
s toq
. - Intially, distance for each
0
cell is0
and distance for each1
isINT_MAX
, which is updated during the BFS. - Pop the cell from queue, and examine its neighbours. If the new calculated distance for neighbour
{i,j}
is smaller, we add{i,j}
toq
and updatedist[i][j]
.
C++
vector<vector<int> > updateMatrix(vector<vector<int> >& matrix) { int rows = matrix.size(); if (rows == 0) return matrix; int cols = matrix[0].size(); vector<vector<int> > dist(rows, vector<int>(cols, INT_MAX)); queue<pair<int, int> > q; for (int i = 0; i < rows; i++) for (int j = 0; j < cols; j++) if (matrix[i][j] == 0) { dist[i][j] = 0; q.push({ i, j }); //Put all 0s in the queue. } int dir[4][2] = { { -1, 0 }, { 1, 0 }, { 0, -1 }, { 0, 1 } }; while (!q.empty()) { pair<int, int> curr = q.front(); q.pop(); for (int i = 0; i < 4; i++) { int new_r = curr.first + dir[i][0], new_c = curr.second + dir[i][1]; if (new_r >= 0 && new_c >= 0 && new_r < rows && new_c < cols) { if (dist[new_r][new_c] > dist[curr.first][curr.second] + 1) { dist[new_r][new_c] = dist[curr.first][curr.second] + 1; q.push({ new_r, new_c }); } } } } return dist; }
Complexity analysis
- Time complexity: O(r⋅c).
-
Since, the new cells are added to the queue only if their current distance is greater than the calculated distance, cells are not likely to be added multiple times.
-
Space complexity: O(r⋅c). Additional O(r⋅c) for queue than in Approach #1
Approach #3 DP Approach [Accepted]
Intuition
The distance of a cell from 0
can be calculated if we know the nearest distance for all the neighbours, in which case the distance is minimum distance of any neightbour + 1. And, instantly, the word come to mind DP!!
For each 1
, the minimum path to 0
can be in any direction. So, we need to check all the 4 direction. In one iteration from top to bottom, we can check left and top directions, and we need another iteration from bottom to top to check for right and bottom direction.
Algorithm
- Iterate the matrix from top to bottom-left to right:
- Update dist[i][j]=min(dist[i][j],min(dist[i][j−1],dist[i−1][j])+1) i.e., minimum of the current dist and distance from top or left neighbour +1, that would have been already calculated previously in the current iteration.
- Now, we need to do the back iteration in the similar manner: from bottom to top-right to left:
- Update dist[i][j]=min(dist[i][j],min(dist[i][j+1],dist[i+1][j])+1) i.e. minimum of current dist and distances calculated from bottom and right neighbours, that would be already available in current iteration.
C++
vector<vector<int> > updateMatrix(vector<vector<int> >& matrix) { int rows = matrix.size(); if (rows == 0) return matrix; int cols = matrix[0].size(); vector<vector<int> > dist(rows, vector<int>(cols, INT_MAX - 100000)); //First pass: check for left and top for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (matrix[i][j] == 0) dist[i][j] = 0; else { if (i > 0) dist[i][j] = min(dist[i][j], dist[i - 1][j] + 1); if (j > 0) dist[i][j] = min(dist[i][j], dist[i][j - 1] + 1); } } } //Second pass: check for bottom and right for (int i = rows - 1; i >= 0; i--) { for (int j = cols - 1; j >= 0; j--) { if (i < rows - 1) dist[i][j] = min(dist[i][j], dist[i + 1][j] + 1); if (j < cols - 1) dist[i][j] = min(dist[i][j], dist[i][j + 1] + 1); } } return dist; }
Complexity analysis
- Time complexity: O(r⋅c). 2 passes of r⋅c each
- Space complexity: O(r⋅c). No additional space required than
dist vector<vector<int> >
public class Solution {
public int[][] updateMatrix(int[][] matrix) {
if(matrix.length==0) return matrix;
for(int i = 0; i<matrix.length; i++)
for(int j = 0; j<matrix[0].length; j++)
if(matrix[i][j]==1&&!hasNeiberZero(i, j,matrix))
matrix[i][j] = matrix.length+matrix[0].length+1;
for(int i = 0; i<matrix.length; i++)
for(int j = 0; j<matrix[0].length; j++)
if(matrix[i][j]==1)
dfs(matrix, i, j, -1);
return matrix;
}
private void dfs(int[][] matrix, int x, int y, int val){
if(x<0||y<0||y>=matrix[0].length||x>=matrix.length||matrix[x][y]<=val)
return;
if(val>0) matrix[x][y] = val;
dfs(matrix, x+1, y, matrix[x][y]+1);
dfs(matrix, x-1, y, matrix[x][y]+1);
dfs(matrix, x, y+1, matrix[x][y]+1);
dfs(matrix, x, y-1, matrix[x][y]+1);
}
private boolean hasNeiberZero(int x, int y, int[][] matrix){
if(x>0&&matrix[x-1][y]==0) return true;
if(x<matrix.length-1&&matrix[x+1][y]==0) return true;
if(y>0&&matrix[x][y-1]==0) return true;
if(y<matrix[0].length-1&&matrix[x][y+1]==0) return true;
return false;
}
}
public class Solution {
int currMin = 12000; // The number of elements of the given matrix will not exceed 10,000, so we can use 12,000 (or anything >10,000) throughout the program as MAX value
public int[][] updateMatrix(int[][] matrix) {
if (matrix.length == 0 || matrix[0].length == 0) {
return matrix;
}
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[i].length; j++) {
if (matrix[i][j] == 1) {
currMin = 12000;
int minDist = dfs(matrix, i, j, 0);
if (minDist < 12000)
matrix[i][j] = minDist;
}
}
}
return matrix;
}
private int dfs(int[][] matrix, int i, int j, int steps) {
if (i < 0 || i >= matrix.length || j < 0 || j >= matrix[0].length ) {
return 12000;
}
if (matrix[i][j] != 1 || steps > currMin) {
return matrix[i][j];
}
matrix[i][j] ^= 12000;
int down = dfs(matrix, i+1, j, steps + 1);
int up = dfs(matrix, i-1, j, steps + 1);
int left = dfs(matrix, i, j-1, steps + 1);
int right = dfs(matrix, i, j+1, steps + 1);
matrix[i][j] ^= 12000;
int minVal = Math.min(left, Math.min(right, Math.min(up, down))) + 1;
currMin = minVal;
return minVal;
}
}
15 days ago reply quote
class Solution {
public:
vector<vector<int>> updateMatrix(vector<vector<int>>& matrix) {
for(int row=0;row<matrix.size();row++){
for(int col=0;col<matrix[0].size();col++){
if(matrix[row][col]==1&&no_adjacent_zero(matrix,row,col))
matrix[row][col]=10000;
}
}
for(int row=0;row<matrix.size();row++){
for(int col=0;col<matrix[0].size();col++){
dfs(matrix,row,col);
}
}
return matrix;
}
bool no_adjacent_zero(vector<vector<int>>& matrix,int row,int col){
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
for(int k=0;k<4;k++){
int new_row=row+next[k][0],new_col=col+next[k][1];
if(new_row<0||new_row>=matrix.size()||new_col<0||new_col>=matrix[0].size())
continue;
if(matrix[new_row][new_col]==0)
return false;
}
return true;
}
void dfs(vector<vector<int>>& matrix,int row,int col){
int next[4][2]={{0,1},{1,0},{0,-1},{-1,0}};
for(int k=0;k<4;k++){
int new_row=row+next[k][0],new_col=col+next[k][1];
if(new_row<0||new_row>=matrix.size()||new_col<0||new_col>=matrix[0].size())
continue;
if(matrix[new_row][new_col]>matrix[row][col]+1){
matrix[new_row][new_col]=matrix[row][col]+1;
dfs(matrix,new_row,new_col);
}
}
}
};
所以这里有一个重点就是周围没有0的点要用一个比较大的值覆盖。上一个DFS的解法是只要有1就赋一个大的值。。