你现在手里有一份大小为 n x n
的 网格 grid
,上面的每个 单元格 都用 0
和 1
标记好了。其中 0
代表海洋,1
代表陆地。
请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,并返回该距离。如果网格上只有陆地或者海洋,请返回 -1
。
我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0)
和 (x1, y1)
这两个单元格之间的距离是|x0 - x1| + |y0 - y1|
。
示例 1:
![](https://assets.leetcode-cn.com/aliyun-lc- upload/uploads/2019/08/17/1336_ex1.jpeg)
**输入:** grid = [[1,0,1],[0,0,0],[1,0,1]]
**输出:** 2
**解释:**
海洋单元格 (1, 1) 和所有陆地单元格之间的距离都达到最大,最大距离为 2。
示例 2:
![](https://assets.leetcode-cn.com/aliyun-lc- upload/uploads/2019/08/17/1336_ex2.jpeg)
**输入:** grid = [[1,0,0],[0,0,0],[0,0,0]]
**输出:** 4
**解释:**
海洋单元格 (2, 2) 和所有陆地单元格之间的距离都达到最大,最大距离为 4。
提示:
n == grid.length
n == grid[i].length
1 <= n <= 100
grid[i][j]
不是 0
就是 1
题目分析 「离陆地区域最远」要求海洋区域距离它最近的陆地区域的曼哈顿距离是最大的。所以我们需要找一个海洋区域,满足它到陆地的最小距离是最大的。
方法一:广度优先搜索 思路
考虑最朴素的方法,即求出每一个海洋区域(grid[i][j] == 0
的区域)的「最近陆地区域」,然后记录下它们的距离,然后在这些距离里面取一个最大值。
对于一个给定的区域 (x, y) ,求它的「最近陆地区域」,可以使用广度优先搜索思想。我们把每个区域的坐标作以及这个区域与 (x, y) 的曼哈顿距离为搜索状态,即 Coordinate
结构体的 x
、y
和 step
属性。findNearestLand
方法实现了广度优先搜索的过程,我们用一个 vis[u][v]
数组记录 (u, v) 区域是否被访问过,在拓展新状态的时候按照如下四个方向:
(x - 1, y)
(x, y + 1)
(x + 1, y)
(x, y - 1)
在这里我们可以把四个方向定义为常量增量数组 dx
和 dy
。
思考:我们需不需要搜索到队列为空才停止 BFS ? 答案是不需要。当我们搜索到一个新入队的区域它的 grid
值为 1
,即这个区域是陆地区域的时候我们就可以停止搜索,因为 BFS 能保证当前的这个区域是最近的陆地区域(BFS 的性质决定了这里求出来的一定是最短路)。
findNearestLand
如果我们找不不到任何一个点是陆地区域则返回 -1
。最终我们把 ans
的初始值置为 -1
,然后与所有的 BFS 结果取最大。
代码实现如下。
代码实现
[sol1-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 class Solution {public : static constexpr int dx[4 ] = {-1 , 0 , 1 , 0 }, dy[4 ] = {0 , 1 , 0 , -1 }; static constexpr int MAX_N = 100 + 5 ; struct Coordinate { int x, y, step; }; int n, m; vector<vector<int >> a; bool vis[MAX_N][MAX_N]; int findNearestLand (int x, int y) { memset (vis, 0 , sizeof vis); queue <Coordinate> q; q.push ({x, y, 0 }); vis[x][y] = 1 ; while (!q.empty ()) { auto f = q.front (); q.pop (); for (int i = 0 ; i < 4 ; ++i) { int nx = f.x + dx[i], ny = f.y + dy[i]; if (!(nx >= 0 && nx <= n - 1 && ny >= 0 && ny <= m - 1 )) { continue ; } if (!vis[nx][ny]) { q.push ({nx, ny, f.step + 1 }); vis[nx][ny] = 1 ; if (a[nx][ny]) { return f.step + 1 ; } } } } return -1 ; } int maxDistance (vector<vector<int >>& grid) { this ->n = grid.size (); this ->m = grid.at (0 ).size (); a = grid; int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < m; ++j) { if (!a[i][j]) { ans = max (ans, findNearestLand (i, j)); } } } return ans; } };
[sol1-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 class Solution { static int [] dx = {-1 , 0 , 1 , 0 }; static int [] dy = {0 , 1 , 0 , -1 }; int n; int [][] grid; public int maxDistance (int [][] grid) { this .n = grid.length; this .grid = grid; int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 0 ) { ans = Math.max(ans, findNearestLand(i, j)); } } } return ans; } public int findNearestLand (int x, int y) { boolean [][] vis = new boolean [n][n]; Queue<int []> queue = new LinkedList <int []>(); queue.offer(new int []{x, y, 0 }); vis[x][y] = true ; while (!queue.isEmpty()) { int [] f = queue.poll(); for (int i = 0 ; i < 4 ; ++i) { int nx = f[0 ] + dx[i], ny = f[1 ] + dy[i]; if (!(nx >= 0 && nx < n && ny >= 0 && ny < n)) { continue ; } if (!vis[nx][ny]) { queue.offer(new int []{nx, ny, f[2 ] + 1 }); vis[nx][ny] = true ; if (grid[nx][ny] == 1 ) { return f[2 ] + 1 ; } } } } return -1 ; } }
复杂度分析
时间复杂度:该算法最多执行 n^2 次 BFS,即我们考虑最坏情况所有的区域都是海洋,那么每一个区域都会进行 BFS。对于每一次 BFS,最坏的情况是找不到陆地区域,我们只能遍历完剩下的 n^2 - 1 个海洋区域,由于 vis
数组确保每个区域只被访问一次,所以单次 BFS 的渐进时间复杂度是 O(n^2),程序的总的渐进时间复杂度是 O(n^4)。
空间复杂度:该算法使用了 vis
数组,渐进空间复杂度为 O(n^2)。
方法二:多源最短路 思路
其实在方法一中我们已经发现我们 BFS 的过程是求最短路的过程,但是这里不是求某一个海洋区域到陆地区域的最短路,而是求所有的海洋区域到陆地区域这个「点集」的最短路。显然这不是一个「单源」最短路问题(SSSP)。在我们学习过的最短路算法中,求解 SSSP 问题的方法有 Dijkstra 算法和 SPFA算法,而求解任意两点之间的最短路一般使用 Floyd 算法。那我们在这里就应该使用 Floyd 算法吗?要考虑这个问题,我们需要分析一下这里使用 Floyd 算法的时间复杂度。我们知道在网格图中求最短路,每个区域(格子)相当于图中的顶点,而每个格子和上下左右四个格子的相邻关系相当于边,我们记顶点的个数为 V,Floyd 算法的时间复杂度为 O(V^3),而这里 V = n^2,所以 O(V^3) = O(n^6),显然是不现实的。
考虑 SSSP 是求一个源点到一个点集中所有点的最短路,而这个问题的本质是求某个点集到另一个点集中所有点的最短路,即「多源最短路」,我们只需要对 Dijkstra 算法或者 SPFA 算法稍作修改。这里以 Dijkstra 算法为例,我们知道堆优化的 Dijkstra 算法实际上是 BFS 的一个变形,把 BFS 中的队列变成了优先队列,在拓展新状态的时候加入了松弛操作。Dijkstra 的堆优化版本第一步是源点入队,我们只需要把它改成源点集合中的所有的点入队就可以实现求「多源最短路」。
思考:为什么? 因为我们这样做相当于建立了一个超级源点 S,这个点与源点集中的 s_0, s_1, s_2 \cdots s_{|V| 都有边,并且权都为 0。这样求源点集到目标点集的最短路就变成了求超级源点 S 到它们的最短路,于是又转化成了 SSSP 问题。
思考:海洋区域和陆地区域,应该哪一个作为源点集? 也许你分析出「我们需要找一个海洋区域,满足它到陆地的最小距离是最大」会把海洋区域作为源点集。我们可以考虑后续的实现,我们知道 Dijkstra 中一个 d
数组用来维护当前源点集到其他点的最短路,而对于源点集中的任意一个点 s,d[s_x][s_y] = 0
,这很好理解,源点到源点的最短路就是 0。如果我们把海洋区域作为源点集、陆地区域作为目标点集,假设 t 是目标点集中的一个点,算法执行结束后 d[t_x][t_y]
就是海洋区域中的点到 t 的最短距离,但是我们却不知道哪些 t 是海洋区域的这些点的「最近陆地区域」,我们也不知道每个 s 距离它的「最近陆地区域」的曼哈顿距离。考虑我们把陆地区域作为源点集、海洋区域作为目标点集,目标点集中的点 t 对应的 d[t_x][t_y]
就是海洋区域 t 对应的距离它的「最近陆地区域」的曼哈顿距离,正是我们需要的,所以应该把陆地区域作为源点集。
最终我们只需要比出 d[t_x][t_y]
的最大值即可。Dijkstra 算法在初始化 d
数组的时候,把每个元素预置为 INF
,所以如果发现最终比出的最大值为 INF
,那么就返回 -1
。
由于这里的边权为 1,也可以直接使用多源 BFS,在这里每个点都只会被松弛一次。
代码实现如下。
代码实现
[sol2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 class Solution {public : static constexpr int MAX_N = 100 + 5 ; static constexpr int INF = int (1E6 ); static constexpr int dx[4 ] = {-1 , 0 , 1 , 0 }, dy[4 ] = {0 , 1 , 0 , -1 }; int n; int d[MAX_N][MAX_N]; struct Status { int v, x, y; bool operator < (const Status &rhs) const { return v > rhs.v; } }; priority_queue <Status> q; int maxDistance (vector<vector<int >>& grid) { this ->n = grid.size (); auto &a = grid; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { d[i][j] = INF; } } for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (a[i][j]) { d[i][j] = 0 ; q.push ({0 , i, j}); } } } while (!q.empty ()) { auto f = q.top (); q.pop (); for (int i = 0 ; i < 4 ; ++i) { int nx = f.x + dx[i], ny = f.y + dy[i]; if (!(nx >= 0 && nx <= n - 1 && ny >= 0 && ny <= n - 1 )) { continue ; } if (f.v + 1 < d[nx][ny]) { d[nx][ny] = f.v + 1 ; q.push ({d[nx][ny], nx, ny}); } } } int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (!a[i][j]) { ans = max (ans, d[i][j]); } } } return (ans == INF) ? -1 : ans; } };
[sol2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 class Solution { public int maxDistance (int [][] grid) { final int INF = 1000000 ; int [] dx = {-1 , 0 , 1 , 0 }; int [] dy = {0 , 1 , 0 , -1 }; int n = grid.length; int [][] d = new int [n][n]; PriorityQueue<int []> queue = new PriorityQueue <int []>(new Comparator <int []>() { public int compare (int [] status1, int [] status2) { return status1[0 ] - status2[0 ]; } }); for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { d[i][j] = INF; } } for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 1 ) { d[i][j] = 0 ; queue.offer(new int []{0 , i, j}); } } } while (!queue.isEmpty()) { int [] f = queue.poll(); for (int i = 0 ; i < 4 ; ++i) { int nx = f[1 ] + dx[i], ny = f[2 ] + dy[i]; if (!(nx >= 0 && nx < n && ny >= 0 && ny < n)) { continue ; } if (f[0 ] + 1 < d[nx][ny]) { d[nx][ny] = f[0 ] + 1 ; queue.offer(new int []{d[nx][ny], nx, ny}); } } } int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 0 ) { ans = Math.max(ans, d[i][j]); } } } return ans == INF ? -1 : ans; } }
[sol2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 class Solution {public : static constexpr int MAX_N = 100 + 5 ; static constexpr int INF = int (1E6 ); static constexpr int dx[4 ] = {-1 , 0 , 1 , 0 }, dy[4 ] = {0 , 1 , 0 , -1 }; int n; int d[MAX_N][MAX_N]; struct Coordinate { int x, y; }; queue <Coordinate> q; int maxDistance (vector<vector<int >>& grid) { this ->n = grid.size (); auto &a = grid; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { d[i][j] = INF; } } for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (a[i][j]) { d[i][j] = 0 ; q.push ({i, j}); } } } while (!q.empty ()) { auto f = q.front (); q.pop (); for (int i = 0 ; i < 4 ; ++i) { int nx = f.x + dx[i], ny = f.y + dy[i]; if (!(nx >= 0 && nx <= n - 1 && ny >= 0 && ny <= n - 1 )) continue ; if (d[nx][ny] > d[f.x][f.y] + 1 ) { d[nx][ny] = d[f.x][f.y] + 1 ; q.push ({nx, ny}); } } } int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (!a[i][j]) { ans = max (ans, d[i][j]); } } } return (ans == INF) ? -1 : ans; } };
[sol2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 class Solution { public int maxDistance (int [][] grid) { final int INF = 1000000 ; int [] dx = {-1 , 0 , 1 , 0 }; int [] dy = {0 , 1 , 0 , -1 }; int n = grid.length; int [][] d = new int [n][n]; Queue<int []> queue = new LinkedList <int []>(); for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { d[i][j] = INF; } } for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 1 ) { d[i][j] = 0 ; queue.offer(new int []{i, j}); } } } while (!queue.isEmpty()) { int [] f = queue.poll(); for (int i = 0 ; i < 4 ; ++i) { int nx = f[0 ] + dx[i], ny = f[1 ] + dy[i]; if (!(nx >= 0 && nx < n && ny >= 0 && ny < n)) { continue ; } if (d[nx][ny] > d[f[0 ]][f[1 ]] + 1 ) { d[nx][ny] = d[f[0 ]][f[1 ]] + 1 ; queue.offer(new int []{nx, ny}); } } } int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 0 ) { ans = Math.max(ans, d[i][j]); } } } return ans == INF ? -1 : ans; } }
[sol2-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 class Solution {public : static constexpr int MAX_N = 100 + 5 ; static constexpr int INF = int (1E6 ); static constexpr int dx[4 ] = {-1 , 0 , 1 , 0 }, dy[4 ] = {0 , 1 , 0 , -1 }; int n; int d[MAX_N][MAX_N]; struct Coordinate { int x, y; }; queue <Coordinate> q; bool inq[MAX_N][MAX_N]; int maxDistance (vector<vector<int >>& grid) { this ->n = grid.size (); auto &a = grid; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { d[i][j] = INF; } } for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (a[i][j]) { d[i][j] = 0 ; q.push ({i, j}); inq[i][j] = 1 ; } } } while (!q.empty ()) { auto f = q.front (); q.pop (); inq[f.x][f.y] = 0 ; for (int i = 0 ; i < 4 ; ++i) { int nx = f.x + dx[i], ny = f.y + dy[i]; if (!(nx >= 0 && nx <= n - 1 && ny >= 0 && ny <= n - 1 )) { continue ; } if (d[nx][ny] > d[f.x][f.y] + 1 ) { d[nx][ny] = d[f.x][f.y] + 1 ; if (!inq[nx][ny]) { q.push ({nx, ny}); inq[nx][ny] = 1 ; } } } } int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (!a[i][j]) { ans = max (ans, d[i][j]); } } } return (ans == INF) ? -1 : ans; } };
[sol2-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 class Solution { public int maxDistance (int [][] grid) { final int INF = 1000000 ; int [] dx = {-1 , 0 , 1 , 0 }; int [] dy = {0 , 1 , 0 , -1 }; int n = grid.length; int [][] d = new int [n][n]; Queue<int []> queue = new LinkedList <int []>(); boolean [][] inq = new boolean [n][n]; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { d[i][j] = INF; } } for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 1 ) { d[i][j] = 0 ; queue.offer(new int []{i, j}); inq[i][j] = true ; } } } while (!queue.isEmpty()) { int [] f = queue.poll(); inq[f[0 ]][f[1 ]] = false ; for (int i = 0 ; i < 4 ; ++i) { int nx = f[0 ] + dx[i], ny = f[1 ] + dy[i]; if (!(nx >= 0 && nx < n && ny >= 0 && ny < n)) { continue ; } if (d[nx][ny] > d[f[0 ]][f[1 ]] + 1 ) { d[nx][ny] = d[f[0 ]][f[1 ]] + 1 ; if (!inq[nx][ny]) { queue.offer(new int []{nx, ny}); inq[nx][ny] = true ; } } } } int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 0 ) { ans = Math.max(ans, d[i][j]); } } } return ans == INF ? -1 : ans; } }
复杂度分析
时间复杂度:考虑这里的「多源最短路」的本质还是「单源最短路」,因此就是 Dijkstra 算法堆优化版本的渐进时间复杂度 O(E \log V),这里 E 为边的个数,约等于 4n^2/2,V 为顶点个数,约等于 n^2,所以这里的渐进时间复杂度为 O(n^2 \log n^2) = O(n^2 \log n);在多源 BFS 当中,由于每个点只能被访问一次,渐进时间复杂度为 O(V+E) = O(n^2);SPFA 算法的理论渐进上界是 O(VE) = O(n^2),但是由于这里的边权都为 1,于是它退化成了 BFS,渐进时间复杂度 O(n^2)。
空间复杂度:该算法使用了 d
数组,渐进空间复杂度为 O(n^2)。
方法三:动态规划 思路
考虑优化方法二中的「把陆地区域作为源点集、海洋区域作为目标点集,求最短路」的过程。我们知道对于每个海洋区域 (x, y),离它最近的陆地区域到它的路径要么从上方或者左方来,要么从右方或者下方来。考虑做两次动态规划,第一次从左上到右下,第二次从右下到左上,记 f(x, y) 为 (x, y) 距离最近的陆地区域的曼哈顿距离,则我们可以推出这样的转移方程:
f(x, y) = \left { \begin{aligned} & 0 & , & (x, y) {\rm , is, land} \ & \min { f(x - 1, y), f(x, y - 1) } + 1 & , & (x, y) {\rm , is,ocean} \end{aligned} \right.
f(x, y) = \left { \begin{aligned} & 0 & , & (x, y) {\rm , is, land} \ & \min { f(x + 1, y), f(x, y + 1) } + 1 & , & (x, y) {\rm , is,ocean} \end{aligned} \right.
我们初始化的时候把陆地的 f
值全部预置为 0
,海洋的 f
全部预置为 INF
,做完两个阶段的动态规划后,我们在所有的不为零的 f[i][j]
中比一个最大值即可,如果最终比较出的最大值为 INF
,就返回 -1
。
思考:如果用 f(x, y) 记录左上方的 DP 结果,g(x, y) 记录右下方的DP结果可行吗? 答案是不可行。因为考虑距离点 (x, y) 最近的点可能既不来自左上方,也不来自右下方,比如它来自右上方,这个时候,第二阶段我们就需要用到第一阶段的计算结果。
代码实现如下。
代码实现
[sol3-C++] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 class Solution {public : static constexpr int MAX_N = 100 + 5 ; static constexpr int INF = int (1E6 ); int f[MAX_N][MAX_N]; int n; int maxDistance (vector<vector<int >>& grid) { this ->n = grid.size (); vector<vector<int >>& a = grid; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { f[i][j] = (a[i][j] ? 0 : INF); } } for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (a[i][j]) { continue ; } if (i - 1 >= 0 ) { f[i][j] = min (f[i][j], f[i - 1 ][j] + 1 ); } if (j - 1 >= 0 ) { f[i][j] = min (f[i][j], f[i][j - 1 ] + 1 ); } } } for (int i = n - 1 ; i >= 0 ; --i) { for (int j = n - 1 ; j >= 0 ; --j) { if (a[i][j]) { continue ; } if (i + 1 < n) { f[i][j] = min (f[i][j], f[i + 1 ][j] + 1 ); } if (j + 1 < n) { f[i][j] = min (f[i][j], f[i][j + 1 ] + 1 ); } } } int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (!a[i][j]) { ans = max (ans, f[i][j]); } } } if (ans == INF) { return -1 ; } else { return ans; } } };
[sol3-Java] 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 class Solution { public int maxDistance (int [][] grid) { final int INF = 1000000 ; int n = grid.length; int [][] f = new int [n][n]; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { f[i][j] = grid[i][j] == 1 ? 0 : INF; } } for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 1 ) { continue ; } if (i - 1 >= 0 ) { f[i][j] = Math.min(f[i][j], f[i - 1 ][j] + 1 ); } if (j - 1 >= 0 ) { f[i][j] = Math.min(f[i][j], f[i][j - 1 ] + 1 ); } } } for (int i = n - 1 ; i >= 0 ; --i) { for (int j = n - 1 ; j >= 0 ; --j) { if (grid[i][j] == 1 ) { continue ; } if (i + 1 < n) { f[i][j] = Math.min(f[i][j], f[i + 1 ][j] + 1 ); } if (j + 1 < n) { f[i][j] = Math.min(f[i][j], f[i][j + 1 ] + 1 ); } } } int ans = -1 ; for (int i = 0 ; i < n; ++i) { for (int j = 0 ; j < n; ++j) { if (grid[i][j] == 0 ) { ans = Math.max(ans, f[i][j]); } } } if (ans == INF) { return -1 ; } else { return ans; } } }
复杂度分析