难度: 中等
题目描述
你现在手里有一份大小为 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]]
输出:2
示例 2:
输入:[[1,0,0],[0,0,0],[0,0,0]]
输出:4
提示:
1 <= grid.length == grid[0].length <= 100
grid[i][j]
不是0
就是1
思路
计算每个海洋到每个陆地的距离需要的时间复杂度是
O
(
n
3
)
O(n^3)
O(n3),但是超时(看到n <= 100
我以为
O
(
n
3
)
O(n^3)
O(n3)会过……)。可以从每个陆地开始计算出到每个海洋的最短路径,这样做时间复杂度仍然是
O
(
n
3
)
O(n^3)
O(n3),但是注意到要求的是距离最近的陆地最远的海洋,所以不用将每个陆地到每个海洋的距离都求出来,只要求出每个海洋到最近的陆地的距离,这可以只用一次dijkstra算法解决,但是由于这道题是网格,用BFS就可以求最短路径,且dijkstra算法没有必要,因为距离近的点一定会先被访问到,不需要松弛。
代码
class Solution {
public:
static constexpr int next[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
int maxDistance(vector<vector<int>> &grid) {
queue<pair<int, int>> q;
int r = grid.size(), c = grid[0].size();
vector<vector<int>> visit(r, vector<int>(c));
for (int i = 0; i < r; ++i)
for (int j = 0; j < c; ++j)
if (grid[i][j] == 1) q.emplace(i, j);
if (q.empty() || q.size() == r * c) return -1;
int step = 0;
while (!q.empty()) {
++step;
int level = q.size();
for (int i = 0; i < level; ++i) {
auto front = q.front();
q.pop();
for (auto &direct : next) {
int nx = front.first + direct[0], ny = front.second + direct[1];
if (nx >= 0 && nx < r && ny >= 0 && ny < c && grid[nx][ny] == 0 && !visit[nx][ny]){
q.emplace(nx, ny);
visit[nx][ny] = true;
}
}
}
}
return step - 1;
}
};