地图分析
你现在手里有一份大小为 N x N 的『地图』(网格) grid,上面的每个『区域』(单元格)都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地,你知道距离陆地区域最远的海洋区域是是哪一个吗?请返回该海洋区域到离它最近的陆地区域的距离。
我们这里说的距离是『曼哈顿距离』( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个区域之间的距离是 |x0 - x1| + |y0 - y1| 。
如果我们的地图上只有陆地或者海洋,请返回 -1。
示例 1:
1 0 1
0 0 0
1 0 1
输入:[[1,0,1],[0,0,0],[1,0,1]]
输出:2
解释:
海洋区域 (1, 1) 和所有陆地区域之间的距离都达到最大,最大距离为 2。
示例 2:
1 0 0
0 0 0
0 0 0
输入:[[1,0,0],[0,0,0],[0,0,0]]
输出:4
解释:
海洋区域 (2, 2) 和所有陆地区域之间的距离都达到最大,最大距离为 4。
提示:
1 <= grid.length == grid[0].length <= 100
grid[i][j] 不是 0 就是 1
class Solution { public: int maxDistance(vector<vector<int>>& grid) { int n = grid.size(); int dp[n][n]; int INF = 201; int ans = -1; for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ int left; int up; if(grid[i][j] == 0){ if(i == 0) up = INF; else if(grid[i-1][j] == 1) up = 1; else up = dp[i-1][j] + 1; if(j == 0) left = INF; else if(grid[i][j-1] == 1) left = 1; else left = dp[i][j-1] + 1; dp[i][j] = min(left,up); } else{ dp[i][j] = INF; } } } for(int i = n-1; i >= 0; i--){ for(int j = n-1; j >= 0; j--){ int right; int down; if(grid[i][j] == 0){ if(i == n-1) down = INF; else if(grid[i+1][j] == 1) down = 1; else down = dp[i+1][j] + 1; if(j == n-1) right = INF; else if(grid[i][j+1] == 1) right = 1; else right = dp[i][j+1] + 1; dp[i][j] = min(dp[i][j],min(right,down)); } else{ dp[i][j] = INF; } } } for(int i = 0; i < n; i++){ for(int j = 0; j < n; j++){ if(grid[i][j] == 0){ ans = max(dp[i][j], ans); } } } return ans>=INF?-1:ans; } };
解题思路:还记得机器人走不同路径那道题不?其实这个跟那个差不多,也可以用dp做。只不过是两遍dp,一遍从左上角到右下角,一遍从右下角到左上角。然后再遍历一遍dp数组,在海洋节点中找到最大距离就好了。
需要注意的是,两遍dp不能分开,必须用一个dp数组。
原因是:
0 1
0 0
如果用两个dp的话,那么在计算第二个dp的时候,图中右下角的最小距离可能是2,因为它计算的时候只用到右边和下边的信息,而没有用到上面的信息。
这样就导致了上图左下角在计算距离的时候不能利用右上角的信息,因为如果共用一个dp,那么右下角在计算的时候就不光计算下边和右边的距离,还要跟本身在第一遍dp的时候记载的距离进行比较,而第一遍dp记载的距离就包含了来自右上角的信息,所以右下角在第二遍dp的时候距离才会被计算为1,也只有当右下角用到了右上角的信息的时候,左下角才能通过右下角用到右上角的信息。