Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit de2ac83

Browse files
✨feat: Add 1162
1 parent 8aa3c60 commit de2ac83

File tree

2 files changed

+195
-0
lines changed

2 files changed

+195
-0
lines changed

‎Index/图论 BFS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@
66
| [773. 滑动谜题](https://leetcode-cn.com/problems/sliding-puzzle/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/sliding-puzzle/solution/gong-shui-san-xie-fa-hui-a-suan-fa-zui-d-3go8/) | 困难 | 🤩🤩🤩🤩 |
77
| [815. 公交路线](https://leetcode-cn.com/problems/bus-routes/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/bus-routes/solution/gong-shui-san-xie-yi-ti-shuang-jie-po-su-1roh/) | 困难 | 🤩🤩🤩🤩 |
88
| [909. 蛇梯棋](https://leetcode-cn.com/problems/snakes-and-ladders/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/snakes-and-ladders/solution/gong-shui-san-xie-bfs-mo-ni-by-ac_oier-woh6/) | 中等 | 🤩🤩🤩🤩 |
9+
| [1162. 地图分析](https://leetcode-cn.com/problems/as-far-from-land-as-possible/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/as-far-from-land-as-possible/solution/gong-shui-san-xie-ru-he-shi-yong-duo-yua-vlea/) | 中等 | 🤩🤩🤩🤩 |
910

Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[1162. 地图分析](https://leetcode-cn.com/problems/as-far-from-land-as-possible/solution/gong-shui-san-xie-ru-he-shi-yong-duo-yua-vlea/)** ,难度为 **中等**
4+
5+
Tag : 「图论 BFS」、「多源 BFS」
6+
7+
8+
9+
你现在手里有一份大小为 $N * N$ 的 网格 $grid,ドル上面的每个 单元格 都用 0ドル$ 和 1ドル$ 标记好了。
10+
11+
其中 0ドル$ 代表海洋,1ドル$ 代表陆地,请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的。
12+
13+
我们这里说的距离是「曼哈顿距离」:$(x0, y0)$ 和 $(x1, y1)$ 这两个单元格之间的距离是 $|x0 - x1| + |y0 - y1|$。
14+
15+
如果网格上只有陆地或者海洋,请返回 $-1$。
16+
17+
示例 1:
18+
![](https://files.mdnice.com/user/9208/4ad5ca7f-bd14-47fc-adc4-760c29ba1bee.png)
19+
```
20+
输入:[[1,0,1],[0,0,0],[1,0,1]]
21+
22+
输出:2
23+
24+
解释:海洋单元格 (1, 1) 和所有陆地单元格之间的距离都达到最大,最大距离为 2。
25+
```
26+
示例 2:
27+
![](https://files.mdnice.com/user/9208/cec486ae-45a4-4235-87b4-89f995f07d3e.png)
28+
```
29+
输入:[[1,0,0],[0,0,0],[0,0,0]]
30+
31+
输出:4
32+
33+
解释:海洋单元格 (2, 2) 和所有陆地单元格之间的距离都达到最大,最大距离为 4。
34+
```
35+
36+
提示:
37+
* 1 <= grid.length == grid[0].length <= 100
38+
* grid[i][j] 不是 0ドル$ 就是 1ドル$
39+
40+
---
41+
42+
### 单源 BFS
43+
44+
通常我们使用 BFS 求最短路,都是针对如下场景:从特定的起点出发,求解到达特定终点的最短距离。
45+
46+
**这是一类特殊的「单源最短路」问题:本质是在一个边权为 1ドル$ 的图上,求从特定「源点」出发到达特定「汇点」的最短路径。**
47+
48+
对于本题,如果套用「单源最短路」做法,我们需要对每个「海洋」位置做一次 BFS:求得每个「海洋」的最近陆地距离,然后在所有的距离中取 $max$ 作为答案。
49+
50+
单次 BFS 的最坏情况需要扫描完整个矩阵,复杂度为 $O(n^2)$。
51+
52+
同时,最多有 $n^2$ 个海洋区域需要做 BFS,因此这样的做法复杂度为 $O(n^4),ドル并且 $O(n^4)$ 可直接取满。
53+
54+
PS. 数据范围为 10ドル^2,ドル理论上是一定会超时,但本题数据较弱,Java 2021年06月28日 可过。
55+
56+
一些细节:为了方便,我们在使用哈希表记录距离时,将二维坐标 $(x, y)$ 转化为对应的一维下标 $idx = x * n + y$ 作为 key 进行存储。
57+
58+
代码:
59+
```Java []
60+
class Solution {
61+
int n;
62+
int[][] grid;
63+
public int maxDistance(int[][] _grid) {
64+
grid = _grid;
65+
n = grid.length;
66+
int ans = -1;
67+
for (int i = 0; i < n; i++) {
68+
for (int j = 0; j < n; j++) {
69+
if (grid[i][j] == 0) {
70+
ans = Math.max(ans, bfs(i, j));
71+
}
72+
}
73+
}
74+
return ans;
75+
}
76+
// 单次 BFS:求解海洋位置 (x,y) 最近的陆地距离
77+
int bfs(int x, int y) {
78+
int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
79+
Deque<int[]> d = new ArrayDeque<>();
80+
Map<Integer, Integer> map = new HashMap<>();
81+
d.addLast(new int[]{x, y});
82+
map.put(x * n + y, 0);
83+
while (!d.isEmpty()) {
84+
int[] poll = d.pollFirst();
85+
int dx = poll[0], dy = poll[1];
86+
int step = map.get(dx * n + dy);
87+
if (grid[dx][dy] == 1) return step;
88+
for (int[] di : dirs) {
89+
int nx = dx + di[0], ny = dy + di[1];
90+
if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
91+
int key = nx * n + ny;
92+
if (map.containsKey(key)) continue;
93+
d.addLast(new int[]{nx, ny});
94+
map.put(key, step + 1);
95+
}
96+
}
97+
return -1;
98+
}
99+
}
100+
```
101+
* 时间复杂度:$O(n^4)$
102+
* 空间复杂度:$O(n^2)$
103+
104+
---
105+
106+
### 多源 BFS
107+
108+
这其实还是道「多源 BFS」入门题。
109+
110+
**与「单源最短路」不同,「多源最短路」问题是求从「多个源点」到达「一个/多个汇点」的最短路径。**
111+
112+
在实现上,最核心的搜索部分,「多源 BFS」与「单源 BFS」并无区别。
113+
114+
**并且通过建立「虚拟源点」的方式,我们可以「多源 BFS」转换回「单源 BFS」问题。**
115+
116+
什么意思?
117+
118+
以本题为例,题面要我们求每个「海洋」区域到最近的「陆地」区域的最大值。
119+
120+
我们可以将「源点/起点」和「汇点/终点」进行反转:**从每个「陆地」区域出发,多个「陆地」区域每次同时向往扩散一圈,每个「海洋」区域被首次覆盖时所对应的圈数,就是「海洋」区域距离最近的「陆地」区域的距离。**
121+
122+
![](https://files.mdnice.com/user/9208/c07cba06-567e-4ac6-a52d-38785687c8fb.png)
123+
124+
不过,这是如何与「单源 BFS」联系起来的呢?
125+
126+
我们可以想象存在一个「虚拟源点」,其与所有「真实源点」(陆地)存在等权的边,那么任意「海洋」区域与「最近的陆地」区域的最短路等价于与「虚拟源点」的最短路:
127+
128+
![](https://files.mdnice.com/user/9208/0a9c7af5-6944-4844-94b5-5b82eb1dd0e6.png)
129+
130+
**实现上,我们并不需要真的将这个虚拟源点建立出来,只需要将所有的「真实源点」进行入队即可。**
131+
132+
这个过程相当于从队列中弹出「虚拟源点」,并把它所能到点(真实源点)进行入队,然后再进行常规的 BFS 即可。
133+
134+
一些细节:实现上为了方便,在进行常规 BFS 时,如果一个「海洋」区域被访问到,说明其被离它「最近的陆地」覆盖到了,修改值为最小距离。这样我们只需要考虑那些值仍然为 0ドル$ 的「海洋」区域即可(代表尚未被更新)。
135+
136+
代码:
137+
```Java
138+
class Solution {
139+
public int maxDistance(int[][] grid) {
140+
int n = grid.length;
141+
Deque<int[]> d = new ArrayDeque<>();
142+
Map<Integer, Integer> map = new HashMap<>();
143+
for (int i = 0; i < n; i++) {
144+
for (int j = 0; j < n; j++) {
145+
if (grid[i][j] == 1) {
146+
d.add(new int[]{i, j});
147+
map.put(i * n + j, 0);
148+
}
149+
}
150+
}
151+
int ans = -1;
152+
int[][] dirs = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
153+
while (!d.isEmpty()) {
154+
int[] poll = d.poll();
155+
int dx = poll[0], dy = poll[1];
156+
int step = map.get(dx * n + dy);
157+
for (int[] di : dirs) {
158+
int nx = dx + di[0], ny = dy + di[1];
159+
if (nx < 0 || nx >= n || ny < 0 || ny >= n) continue;
160+
if (grid[nx][ny] != 0) continue;
161+
grid[nx][ny] = step + 1;
162+
d.add(new int[]{nx, ny});
163+
map.put(nx * n + ny, step + 1);
164+
ans = Math.max(ans, step + 1);
165+
}
166+
}
167+
return ans;
168+
}
169+
}
170+
```
171+
* 时间复杂度:$O(n^2)$
172+
* 空间复杂度:$O(n^2)$
173+
174+
---
175+
176+
### 总结
177+
178+
今天我们介绍了「多源 BFS」,通过建立「虚拟源点」,我们可以将其转化回「单源 BFS」问题。
179+
180+
实现上我们只需要将所有的「真实源点」进行入队,然后再进行 BFS 即可。
181+
182+
看起来两者区别不大,但其本质是通过源点/汇点转换,应用常规的 Flood Fill 将多次朴素 BFS 转化为一次 BFS,可以有效降低我们算法的时间复杂度。
183+
184+
---
185+
186+
### 最后
187+
188+
这是我们「刷穿 LeetCode」系列文章的第 `No.1162` 篇,系列开始于 2021年01月01日,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先将所有不带锁的题目刷完。
189+
190+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
191+
192+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
193+
194+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /