542. 01 Matrix(深搜/广搜/DP的题目)
2017-08-21 23:20
513 查看
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:
Output:
Example 2:
Input:
Output:
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.
解答(摘自Solution):
Intuition
Do what the question says.
Algorithm
Initialize
Iterate over the matrix.
If cell is
Else, for each
Iterate over the entire matrix
If the cell is
If the distance is smaller than the current distance, update it.
C++
Complexity Analysis
Time complexity: O((r
\cdot c)^2)O((r⋅c)2).
Iterating over the entire matrix for each
Space complexity: O(r
\cdot c)O(r⋅c).
No extra space required than the
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
for each
during the BFS, we know that the
Think again: But, in this approach, we will only be able to update the distance of one
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
and thereby, updating the distances of all the
Algorithm
For our BFS routine, we keep a queue,
be examined next.
We start by adding all the cells with
Intially, distance for each
distance for each
which is updated during the BFS.
Pop the cell from queue, and examine its neighbours. If the new calculated distance for neighbour
smaller, we add
update
C++
Complexity analysis
Time complexity: O(r
\cdot c)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
\cdot c)O(r⋅c).
Additional O(r
\cdot c)O(r⋅c) for
queue than in Approach #1
Intuition
The distance of a cell from
the neighbours, in which case the distance is minimum distance of any neightbour + 1. And, instantly, the word come to mind DP!!
For each
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 \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) 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 \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) i.e.
minimum of current dist and distances calculated from bottom and right neighbours, that would be already available in current iteration.
C++
Complexity analysis
Time complexity: O(r
\cdot c)O(r⋅c).
2 passes of r
\cdot cr⋅c each
Space complexity: O(r
\cdot c)O(r⋅c).
No additional space required than
注:
暴力法很好懂,DFS个人不感兴趣。。。DP的想法是:对于某一个位置,它到最近的0的距离=它的邻居中离这个0最近的那个+1(如果邻居有0那么直接赋0就好了)。注意第一趟要检查的是往上和往左,第二趟是下、右,不能混起来。。
其实我比较关心的是DFS怎么做(来自Discuss,Java版):
这个版本要清晰一点:
另一个版本的DFS:
The distance between two adjacent cells is 1.
Example 1:
Input:
0 0 0 0 1 0 0 0 0
Output:
0 0 0 0 1 0 0 0 0
Example 2:
Input:
0 0 0 0 1 0 1 1 1
Output:
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.
解答(摘自Solution):
Approach #1 Brute force [Time Limit Exceeded]
IntuitionDo what the question says.
Algorithm
Initialize
dist[i][j]=INT_MAXfor all
{i,j}cells.
Iterate over the matrix.
If cell is
0,
dist[i][j]=0,
Else, for each
1cell,
Iterate over the entire matrix
If the cell is
0, calculate its distance from current cell as
abs(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
\cdot c)^2)O((r⋅c)2).
Iterating over the entire matrix for each
1in the matrix.
Space complexity: O(r
\cdot c)O(r⋅c).
No extra space required than the
vector<vector<int> > dist
Approach #2 Using BFS [Accepted]
IntuitionA 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
0found
for each
1. As soon as a
0appears
during the BFS, we know that the
0is 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
1using
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
0s
and thereby, updating the distances of all the
1s in the path.
Algorithm
For our BFS routine, we keep a queue,
qto maintain the queue of cells to
be examined next.
We start by adding all the cells with
0s to
q.
Intially, distance for each
0cell is
0and
distance for each
1is
INT_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}to
qand
update
dist[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
\cdot c)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
\cdot c)O(r⋅c).
Additional O(r
\cdot c)O(r⋅c) for
queue than in Approach #1
Approach #3 DP Approach [Accepted]
IntuitionThe distance of a cell from
0can 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
0can
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 \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) 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 \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) 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
\cdot c)O(r⋅c).
2 passes of r
\cdot cr⋅c each
Space complexity: O(r
\cdot c)O(r⋅c).
No additional space required than
dist vector<vector<int> >
注:
暴力法很好懂,DFS个人不感兴趣。。。DP的想法是:对于某一个位置,它到最近的0的距离=它的邻居中离这个0最近的那个+1(如果邻居有0那么直接赋0就好了)。注意第一趟要检查的是往上和往左,第二趟是下、右,不能混起来。。
其实我比较关心的是DFS怎么做(来自Discuss,Java版):
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
另一个版本的DFS:
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就赋一个大的值。。
相关文章推荐
- Leetcode-542. 01 Matrix
- leetcode 542. 01 Matrix
- leetcode-542-01 Matrix
- 01 Matrix 杭电2015年12月校赛F (二维DP)
- [Leetcode] 542. 01 Matrix 解题报告
- 542. 01 Matrix
- 算法分析与设计课程06——542. 01 Matrix(Medium)
- 542. 01 Matrix
- 542. 01 Matrix
- 【leetcode】542. 01 Matrix的解法总结
- HDU-2870 Largest Submatrix (线性dp 最大01矩阵)(2009 Multi-University Training Contest 7 )
- 542. 01 Matrix
- 542. 01 Matrix
- 542. 01 Matrix
- leetcode 542. 01 Matrix 距离0最近的距离 + 正反遍历 + 动态规划DP
- 542. 01 Matrix
- 542. 01 Matrix
- [leetcode]-542 01 Matrix
- LeetCode 542. 01 Matrix
- leetcode 542. 01 Matrix