Skip to content

Commit 6e6b722

Browse files
committed
✨feat: Add 1036
1 parent ef7104a commit 6e6b722

File tree

2 files changed

+208
-0
lines changed

2 files changed

+208
-0
lines changed

Index/图论 BFS.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
| [863. 二叉树中所有距离为 K 的结点](https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/all-nodes-distance-k-in-binary-tree/solution/gong-shui-san-xie-yi-ti-shuang-jie-jian-x6hak/) | 中等 | 🤩🤩🤩🤩 |
1010
| [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/) | 中等 | 🤩🤩🤩🤩 |
1111
| [1034. 边界着色](https://leetcode-cn.com/problems/coloring-a-border/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/coloring-a-border/solution/gong-shui-san-xie-tu-lun-sou-suo-zhuan-t-snvw/) | 中等 | 🤩🤩🤩🤩 |
12+
| [1036. 逃离大迷宫](https://leetcode-cn.com/problems/escape-a-large-maze/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/escape-a-large-maze/solution/gong-shui-san-xie-bfs-gei-ding-zhang-ai-8w63o/) | 中等 | 🤩🤩🤩🤩 |
1213
| [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/) | 中等 | 🤩🤩🤩🤩 |
1314
| [2059. 转化数字的最小运算数](https://leetcode-cn.com/problems/minimum-operations-to-convert-number/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/minimum-operations-to-convert-number/solution/gong-shui-san-xie-shuang-xiang-bfs-mo-ba-uckg/) | 中等 | 🤩🤩🤩🤩🤩 |
1415
| [LCP 07. 传递信息](https://leetcode-cn.com/problems/chuan-di-xin-xi/) | [LeetCode 题解链接](https://leetcode-cn.com/problems/chuan-di-xin-xi/solution/gong-shui-san-xie-tu-lun-sou-suo-yu-dong-cyxo/) | 简单 | 🤩🤩🤩🤩 |
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,207 @@
1+
### 题目描述
2+
3+
这是 LeetCode 上的 **[1036. 逃离大迷宫](https://leetcode-cn.com/problems/escape-a-large-maze/solution/gong-shui-san-xie-bfs-gei-ding-zhang-ai-8w63o/)** ,难度为 **困难**
4+
5+
Tag : 「几何」、「BFS」
6+
7+
8+
9+
在一个 $10^6$ x $10^6$ 的网格中,每个网格上方格的坐标为 $(x, y)$ 。
10+
11+
现在从源方格 $source = [s_x, s_y]$ 开始出发,意图赶往目标方格 $target = [t_x, t_y]$ 。
12+
13+
数组 $blocked$ 是封锁的方格列表,其中每个 $blocked[i] = [x_i, y_i]$ 表示坐标为 $(x_i, y_i)$ 的方格是禁止通行的。
14+
15+
每次移动,都可以走到网格中在四个方向上相邻的方格,只要该方格 不 在给出的封锁列表 $blocked$ 上。同时,不允许走出网格。
16+
17+
只有在可以通过一系列的移动从源方格 $source$ 到达目标方格 $target$ 时才返回 $true$。否则,返回 $false$。
18+
19+
示例 1:
20+
```
21+
输入:blocked = [[0,1],[1,0]], source = [0,0], target = [0,2]
22+
23+
输出:false
24+
25+
解释:
26+
从源方格无法到达目标方格,因为我们无法在网格中移动。
27+
无法向北或者向东移动是因为方格禁止通行。
28+
无法向南或者向西移动是因为不能走出网格。
29+
```
30+
示例 2:
31+
```
32+
输入:blocked = [], source = [0,0], target = [999999,999999]
33+
34+
输出:true
35+
36+
解释:
37+
因为没有方格被封锁,所以一定可以到达目标方格。
38+
```
39+
40+
提示:
41+
* $0 <= blocked.length <= 200$
42+
* $blocked[i].length == 2$
43+
* $0 <= xi, yi < 10^6$
44+
* $source.length == target.length == 2$
45+
* $0 <= sx, sy, tx, ty < 10^6$
46+
* $source != target$
47+
* 题目数据保证 $source$ 和 $target$ 不在封锁列表内
48+
49+
---
50+
51+
### BFS + 给定障碍物所能围成的最大面积
52+
53+
为了方便,我们用 $s$ 代指 $source$,用 $t$ 代指 $target$,用 $n$ 来代指 $blocked$ 大小。
54+
55+
整理题意为:在一个足够大的空间里,有少数的障碍物,问两点是否连通。
56+
57+
当两点相隔较远时,常规的 `BFS` 做法可能会搜完整个棋盘,而棋盘大小为 $10^6 * 10^6$,会 `TLE`
58+
59+
考虑什么情况下两点会不连通?
60+
61+
当两个点中的任意一点被障碍物围住时,两点将无法连通。
62+
63+
一个很容易想到的思路是:**从 $s$ 跑一遍 `BFS`,然后从 $t$ 跑一遍 `BFS`,同时设定一个最大访问点数量 `MAX`,若从两者出发能够访问的点数量都能超过 `MAX`,说明两点均没有被围住,最终必然会联通。**
64+
65+
考虑如何敲定 `MAX` 的取值范围?直观感受,`MAX` 应该是一个与 $blocked$ 大小相关的数。
66+
67+
但第一反应还是想从单秒计算量上界进行反推,两边 `BFS` 的复杂度均为 $O(\max)$,因此直接设定 `MAX = 1e5` 应该是比较合适的。
68+
69+
更小的 `MAX` 需要证明:**在给定数量障碍物的前提下,障碍物所能围成的最大面积为多少。**
70+
71+
首先,容易想到:**任何一条封闭图形的直边都可以通过调整为斜边来围成更大的面积:**
72+
73+
![image.png](https://pic.leetcode-cn.com/1641855571-IOaJZJ-image.png)
74+
75+
**即组成封闭图形的边不可能有直边,同时由于是封闭图形,因此斜边直接必然是单点衔接,而不可能是平行(无法封闭)。**
76+
77+
同时,**想要达到最大面积,应当尽可能利用边界作为围成图形的某些边。**
78+
79+
利用边界所能围成的最大封面图形 **可以是**「由边界提供两边,障碍物提供一边的三角形」。
80+
81+
如果不是该形状,则可以通过调整障碍物的直边为一条完整的斜边,来组成封闭三角形,围成面积不会变小:
82+
83+
![image.png](https://pic.leetcode-cn.com/1641856898-BYFygs-image.png)
84+
85+
即给定 $n$ 的情况下,根据「等差数列求和」可知,最大所能围成的面积为 $1 + 2 + ... + n - 1 = \frac{n * (n - 1)}{2}$。
86+
87+
因此如果从 $s$ 和 $t$ 出发,能够访问的点数超过 $\frac{n * (n - 1)}{2}$ 个,那么两点并没有被围住,必然联通。
88+
89+
最后,为了在 `BFS` 过程中记录某些点被访问过,可以通过计算某个位置哈希值(数值)来实现。
90+
91+
**代码(感谢 [@🍭可乐可乐吗QAQ](/u/littletime_cc/)[@Benhao](/u/himymben/) 同学提供的其他语言版本):**
92+
```Java
93+
class Solution {
94+
int EDGE = (int)1e6, MAX = (int)1e5;
95+
long BASE = 131L;
96+
Set<Long> set = new HashSet<>();
97+
int[][] dir = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
98+
public boolean isEscapePossible(int[][] blocked, int[] s, int[] t) {
99+
for (int[] p : blocked) set.add(p[0] * BASE + p[1]);
100+
int n = blocked.length;
101+
MAX = n * (n - 1) / 2; // 可直接使用 1e5
102+
return check(s, t) && check(t, s);
103+
}
104+
boolean check(int[] a, int[] b) {
105+
Set<Long> vis = new HashSet<>();
106+
Deque<int[]> d = new ArrayDeque<>();
107+
d.addLast(a);
108+
vis.add(a[0] * BASE + a[1]);
109+
while (!d.isEmpty() && vis.size() <= MAX) {
110+
int[] poll = d.pollFirst();
111+
int x = poll[0], y = poll[1];
112+
if (x == b[0] && y == b[1]) return true;
113+
for (int[] di : dir) {
114+
int nx = x + di[0], ny = y + di[1];
115+
if (nx < 0 || nx >= EDGE || ny < 0 || ny >= EDGE) continue;
116+
long hash = nx * BASE + ny;
117+
if (set.contains(hash)) continue;
118+
if (vis.contains(hash)) continue;
119+
d.addLast(new int[]{nx, ny});
120+
vis.add(hash);
121+
}
122+
}
123+
return vis.size() > MAX;
124+
}
125+
}
126+
```
127+
128+
129+
```C++
130+
class Solution {
131+
public:
132+
int EDGE = 1e6, MAX = 1e5;
133+
long long BASE = 13331;
134+
unordered_set<long long> set;
135+
int dir[4][2] = { {1, 0}, {-1, 0}, {0, 1}, {0, -1} };
136+
bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& s, vector<int>& t) {
137+
for(auto& p : blocked) set.insert(p[0] * BASE + p[1]);
138+
int n = blocked.size();
139+
MAX = n * (n - 1) / 2; // 可直接使用 1e5
140+
return check(s, t) and check(t, s);
141+
}
142+
bool check(vector<int>& a, vector<int>& b){
143+
unordered_set<long long> vis;
144+
queue< pair<int,int> > q;
145+
q.push( {a[0], a[1]});
146+
vis.insert(a[0] * BASE + a[1]);
147+
while(q.size() and vis.size() <= MAX){
148+
auto t = q.front();
149+
q.pop();
150+
int x = t.first, y = t.second;
151+
if(x == b[0] and y == b[1]) return true;
152+
for(int i = 0; i < 4; i++){
153+
int nx = x + dir[i][0], ny = y + dir[i][1];
154+
if(nx < 0 or nx >= EDGE or ny < 0 or ny >= EDGE) continue;
155+
if(set.count(nx * BASE + ny)) continue;
156+
if(vis.count(nx * BASE + ny)) continue;
157+
q.push( {nx, ny} );
158+
vis.insert(nx * BASE + ny);
159+
}
160+
}
161+
return vis.size() > MAX;
162+
}
163+
};
164+
```
165+
166+
167+
```Python
168+
EDGE, MAX, BASE, DIR = int(1e6), int(1e5), 131, [(1, 0), (-1, 0), (0, 1), (0, -1)]
169+
class Solution:
170+
def isEscapePossible(self, blocked: List[List[int]], source: List[int], target: List[int]) -> bool:
171+
block = {p[0] * BASE + p[1] for p in blocked}
172+
n = len(blocked)
173+
MAX = n * (n-1)//2 # 可直接使用 1e5
174+
def check(a, b):
175+
vis = {a[0] * BASE + a[1]}
176+
d = deque([a])
177+
while len(d) and len(vis) <= MAX:
178+
x, y = d.popleft()
179+
if x == b[0] and y == b[1]:
180+
return True
181+
for dx, dy in DIR:
182+
nx, ny = x + dx, y + dy
183+
if nx < 0 or nx >= EDGE or ny < 0 or ny >= EDGE:
184+
continue
185+
h = nx * BASE + ny
186+
if h in block or h in vis:
187+
continue
188+
d.append((nx, ny))
189+
vis.add(h)
190+
return len(vis) > MAX
191+
return check(source, target) and check(target, source)
192+
```
193+
* 时间复杂度:令 $n$ 为 $blocked$ 大小,两次 `BFS` 的最大访问点数为 $\frac{n * (n - 1)}{2}$。整体复杂度为 $O(n^2)$
194+
* 空间复杂度:两次 `BFS` 的最大访问点数为 $\frac{n * (n - 1)}{2}$。整体复杂度为 $O(n^2)$
195+
196+
---
197+
198+
### 最后
199+
200+
这是我们「刷穿 LeetCode」系列文章的第 `No.1036` 篇,系列开始于 2021/01/01,截止于起始日 LeetCode 上共有 1916 道题目,部分是有锁题,我们将先把所有不带锁的题目刷完。
201+
202+
在这个系列文章里面,除了讲解解题思路以外,还会尽可能给出最为简洁的代码。如果涉及通解还会相应的代码模板。
203+
204+
为了方便各位同学能够电脑上进行调试和提交代码,我建立了相关的仓库:https://github.com/SharingSource/LogicStack-LeetCode
205+
206+
在仓库地址里,你可以看到系列文章的题解链接、系列文章的相应代码、LeetCode 原题链接和其他优选题解。
207+

0 commit comments

Comments
 (0)