7070
7171<!-- solution:start -->
7272
73- ### 方法一
73+ ### 方法一:DFS
74+
75+ 题目相当于在一个 $10^6 \times 10^6$ 的网格中,给定源点和目标点,以及一小部分被封锁的点,问是否可以从源点到达目标点。
76+
77+ 由于被封锁的点数量很少,最终能封锁的区域大小不超过 $|blocked|^2 / 2$,因此,我们可以从源点和目标点出发,进行深度优先搜索,直到搜索到目标点或者搜索到的点数超过 $|blocked|^2 / 2$,如果都满足,则返回 $\textit{true}$。否则返回 $\textit{false}$。
78+
79+ 时间复杂度 $O(m)$,空间复杂度 $O(m)$,其中 $m$ 是被封锁的区域的大小,本题中 $m \leq |blocked|^2 / 2 = 200^2 / 2 = 20000$。
7480
7581<!-- tabs:start -->
7682
@@ -81,94 +87,108 @@ class Solution:
8187 def isEscapePossible (
8288 self , blocked : List[List[int ]], source : List[int ], target : List[int ]
8389 ) -> bool :
84- def dfs (source , target , seen ):
85- x, y = source
86- if (
87- not (0 <= x < 10 ** 6 and 0 <= y < 10 ** 6 )
88- or (x, y) in blocked
89- or (x, y) in seen
90- ):
91- return False
92- seen.add((x, y))
93- if len (seen) > 20000 or source == target:
90+ def dfs (source : List[int ], target : List[int ], vis : set ) -> bool :
91+ vis.add(tuple (source))
92+ if len (vis) > m:
9493 return True
95- for a, b in [[0 , - 1 ], [0 , 1 ], [1 , 0 ], [- 1 , 0 ]]:
96- next = [x + a, y + b]
97- if dfs(next , target, seen):
98- return True
94+ for a, b in pairwise(dirs):
95+ x, y = source[0 ] + a, source[1 ] + b
96+ if 0 <= x < n and 0 <= y < n and (x, y) not in s and (x, y) not in vis:
97+ if [x, y] == target or dfs([x, y], target, vis):
98+ return True
9999 return False
100100
101- blocked = set ((x, y) for x, y in blocked)
101+ s = {(x, y) for x, y in blocked}
102+ dirs = (- 1 , 0 , 1 , 0 , - 1 )
103+ n = 10 ** 6
104+ m = len (blocked) ** 2 // 2
102105 return dfs(source, target, set ()) and dfs(target, source, set ())
103106```
104107
105108#### Java
106109
107110``` java
108111class Solution {
109- private int [][] dirs = new int [][] {{1 , 0 }, {- 1 , 0 }, {0 , 1 }, {0 , - 1 }};
110- private static final int N = (int ) 1e6 ;
111- private Set<Integer > blocked;
112+ private final int n = (int ) 1e6 ;
113+ private int m;
114+ private Set<Long > s = new HashSet<> ();
115+ private final int [] dirs = {- 1 , 0 , 1 , 0 , - 1 };
112116
113117 public boolean isEscapePossible (int [][] blocked , int [] source , int [] target ) {
114- this . blocked = new HashSet<> ();
115- for (int [] b : blocked) {
116- this . blocked. add(b[0 ] * N + b[1 ]);
118+ for (var b : blocked) {
119+ s. add(f(b[0 ], b[1 ]));
117120 }
118- return dfs(source, target, new HashSet<> ()) && dfs(target, source, new HashSet<> ());
119- }
120-
121- private boolean dfs (int [] source , int [] target , Set<Integer > seen ) {
121+ m = blocked. length * blocked. length / 2 ;
122122 int sx = source[0 ], sy = source[1 ];
123123 int tx = target[0 ], ty = target[1 ];
124- if (sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N
125- || blocked. contains(sx * N + sy) || seen. contains(sx * N + sy)) {
126- return false ;
127- }
128- seen. add(sx * N + sy);
129- if (seen. size() > 20000 || (sx == target[0 ] && sy == target[1 ])) {
124+ return dfs(sx, sy, tx, ty, new HashSet<> ()) && dfs(tx, ty, sx, sy, new HashSet<> ());
125+ }
126+
127+ private boolean dfs (int sx , int sy , int tx , int ty , Set<Long > vis ) {
128+ if (vis. size() > m) {
130129 return true ;
131130 }
132- for (int [] dir : dirs) {
133- if (dfs(new int [] {sx + dir[0 ], sy + dir[1 ]}, target, seen)) {
134- return true ;
131+ for (int k = 0 ; k < 4 ; ++ k) {
132+ int x = sx + dirs[k], y = sy + dirs[k + 1 ];
133+ if (x >= 0 && x < n && y >= 0 && y < n) {
134+ if (x == tx && y == ty) {
135+ return true ;
136+ }
137+ long key = f(x, y);
138+ if (! s. contains(key) && vis. add(key) && dfs(x, y, tx, ty, vis)) {
139+ return true ;
140+ }
135141 }
136142 }
137143 return false ;
138144 }
145+
146+ private long f (int i , int j ) {
147+ return (long ) i * n + j;
148+ }
139149}
140150```
141151
142152#### C++
143153
144154``` cpp
145- typedef unsigned long long ULL;
146-
147155class Solution {
148156public:
149- vector<vector<int >> dirs = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
150- unordered_set<ULL > blocked;
151- int N = 1e6;
152-
153157 bool isEscapePossible(vector<vector<int >>& blocked, vector<int >& source, vector<int >& target) {
154- this->blocked.clear();
155- for (auto& b : blocked) this->blocked.insert((ULL) b[0] * N + b[1]);
156- unordered_set<ULL> s1;
157- unordered_set<ULL> s2;
158- return dfs(source, target, s1) && dfs(target, source, s2);
159- }
160-
161- bool dfs (vector<int >& source, vector<int >& target, unordered_set<ULL >& seen) {
158+ const int n = 1e6;
159+ int m = blocked.size() * blocked.size() / 2;
160+ using ll = long long;
161+ unordered_set<ll > s;
162+ const int dirs[ 5] = {-1, 0, 1, 0, -1};
163+ auto f = [ &] (int i, int j) {
164+ return (ll) i * n + j;
165+ };
166+ for (const auto& b : blocked) {
167+ s.insert(f(b[ 0] , b[ 1] ));
168+ }
162169 int sx = source[ 0] , sy = source[ 1] ;
163170 int tx = target[ 0] , ty = target[ 1] ;
164- if (sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N || blocked.count((ULL) sx * N + sy) || seen.count((ULL) sx * N + sy)) return 0;
165- seen.insert((ULL) sx * N + sy);
166- if (seen.size() > 20000 || (sx == target[ 0] && sy == target[ 1] )) return 1;
167- for (auto& dir : dirs) {
168- vector<int > next = {sx + dir[ 0] , sy + dir[ 1] };
169- if (dfs(next, target, seen)) return 1;
170- }
171- return 0;
171+ unordered_set<ll > vis1, vis2;
172+ auto dfs = [ &] (this auto&& dfs, int sx, int sy, int tx, int ty, unordered_set<ll >& vis) -> bool {
173+ vis.insert(f(sx, sy));
174+ if (vis.size() > m) {
175+ return true;
176+ }
177+ for (int k = 0; k < 4; ++k) {
178+ int x = sx + dirs[ k] , y = sy + dirs[ k + 1] ;
179+ if (x >= 0 && x < n && y >= 0 && y < n) {
180+ if (x == tx && y == ty) {
181+ return true;
182+ }
183+ auto key = f(x, y);
184+ if (!s.contains(key) && !vis.contains(key) && dfs(x, y, tx, ty, vis)) {
185+ return true;
186+ }
187+ }
188+ }
189+ return false;
190+ };
191+ return dfs(sx, sy, tx, ty, vis1) && dfs(tx, ty, sx, sy, vis2);
172192 }
173193};
174194```
@@ -177,84 +197,156 @@ public:
177197
178198```go
179199func isEscapePossible(blocked [][]int, source []int, target []int) bool {
180- const N = 1e6
181- dirs := [4][2]int{{0, -1}, {0, 1}, {1, 0}, {-1, 0}}
182- block := make(map[int]bool)
200+ const n = 1_000_000
201+ m := len(blocked) * len(blocked) / 2
202+ dirs := [5]int{-1, 0, 1, 0, -1}
203+
204+ f := func(i, j int) int64 {
205+ return int64(i*n + j)
206+ }
207+
208+ s := make(map[int64]bool)
183209 for _, b := range blocked {
184- block[ b[0]*N+ b[1]] = true
210+ s[f( b[0], b[1]) ] = true
185211 }
186- var dfs func(source, target []int, seen map[int]bool) bool
187- dfs = func(source, target []int, seen map[int]bool) bool {
188- sx, sy := source[0], source[1]
189- tx, ty := target[0], target[1]
190- if sx < 0 || sx >= N || sy < 0 || sy >= N || tx < 0 || tx >= N || ty < 0 || ty >= N || block[sx*N+sy] || seen[sx*N+sy] {
191- return false
192- }
193- seen[sx*N+sy] = true
194- if len(seen) > 20000 || (sx == target[0] && sy == target[1]) {
212+
213+ var dfs func(sx, sy, tx, ty int, vis map[int64]bool) bool
214+ dfs = func(sx, sy, tx, ty int, vis map[int64]bool) bool {
215+ key := f(sx, sy)
216+ vis[key] = true
217+ if len(vis) > m {
195218 return true
196219 }
197- for _, dir := range dirs {
198- next := []int{sx + dir[0], sy + dir[1]}
199- if dfs(next, target, seen) {
200- return true
220+ for k := 0; k < 4; k++ {
221+ x, y := sx+dirs[k], sy+dirs[k+1]
222+ if x >= 0 && x < n && y >= 0 && y < n {
223+ if x == tx && y == ty {
224+ return true
225+ }
226+ key := f(x, y)
227+ if !s[key] && !vis[key] && dfs(x, y, tx, ty, vis) {
228+ return true
229+ }
201230 }
202231 }
203232 return false
204233 }
205- s1, s2 := make(map[int]bool), make(map[int]bool)
206- return dfs(source, target, s1) && dfs(target, source, s2)
234+
235+ sx, sy := source[0], source[1]
236+ tx, ty := target[0], target[1]
237+ return dfs(sx, sy, tx, ty, map[int64]bool{}) && dfs(tx, ty, sx, sy, map[int64]bool{})
207238}
208239```
209240
210- #### Rust
241+ #### TypeScript
211242
212- ``` rust
213- use std :: collections :: {HashSet , VecDeque };
243+ ``` ts
244+ function isEscapePossible(blocked : number [][], source : number [], target : number []): boolean {
245+ const n = 10 ** 6 ;
246+ const m = (blocked .length ** 2 ) >> 1 ;
247+ const dirs = [- 1 , 0 , 1 , 0 , - 1 ];
214248
215- const BOUNDARY : i32 = 1_000_000 ;
216- const MAX : usize = 20000 ;
249+ const s = new Set < number >() ;
250+ const f = ( i : number , j : number ) : number => i * n + j ;
217251
218- impl Solution {
219- pub fn is_escape_possible (blocked : Vec <Vec <i32 >>, source : Vec <i32 >, target : Vec <i32 >) -> bool {
220- let mut block = HashSet :: with_capacity (blocked . len ());
221- for b in blocked . iter () {
222- block . insert ((b [0 ], b [1 ]));
223- }
224- bfs (& block , & source , & target ) && bfs (& block , & target , & source )
252+ for (const [x, y] of blocked ) {
253+ s .add (f (x , y ));
225254 }
255+
256+ const dfs = (sx : number , sy : number , tx : number , ty : number , vis : Set <number >): boolean => {
257+ vis .add (f (sx , sy ));
258+ if (vis .size > m ) {
259+ return true ;
260+ }
261+ for (let k = 0 ; k < 4 ; k ++ ) {
262+ const x = sx + dirs [k ],
263+ y = sy + dirs [k + 1 ];
264+ if (x >= 0 && x < n && y >= 0 && y < n ) {
265+ if (x === tx && y === ty ) {
266+ return true ;
267+ }
268+ const key = f (x , y );
269+ if (! s .has (key ) && ! vis .has (key ) && dfs (x , y , tx , ty , vis )) {
270+ return true ;
271+ }
272+ }
273+ }
274+ return false ;
275+ };
276+
277+ return (
278+ dfs (source [0 ], source [1 ], target [0 ], target [1 ], new Set ()) &&
279+ dfs (target [0 ], target [1 ], source [0 ], source [1 ], new Set ())
280+ );
226281}
282+ ```
227283
228- fn bfs (block : & HashSet <(i32 , i32 )>, source : & Vec <i32 >, target : & Vec <i32 >) -> bool {
229- let dir = vec! [(- 1 , 0 ), (1 , 0 ), (0 , - 1 ), (0 , 1 )];
284+ #### Rust
230285
231- let mut queue = VecDeque :: new ();
232- let mut vis = HashSet :: new ();
233- queue . push_back ((source [0 ], source [1 ]));
234- vis . insert ((source [0 ], source [1 ]));
286+ ``` rust
287+ use std :: collections :: HashSet ;
235288
236- while ! queue . is_empty () && vis . len () < MAX {
237- let (x , y ) = queue . pop_front (). unwrap ();
238- if x == target [0 ] && y == target [1 ] {
239- return true ;
289+ impl Solution {
290+ pub fn is_escape_possible (blocked : Vec <Vec <i32 >>, source : Vec <i32 >, target : Vec <i32 >) -> bool {
291+ const N : i64 = 1_000_000 ;
292+ let m = (blocked . len () * blocked . len ()) as i64 / 2 ;
293+
294+ let f = | i : i64 , j : i64 | -> i64 { i * N + j };
295+
296+ let mut s : HashSet <i64 > = HashSet :: new ();
297+ for b in & blocked {
298+ s . insert (f (b [0 ] as i64 , b [1 ] as i64 ));
240299 }
241- for (dx , dy ) in dir . iter () {
242- let (nx , ny ) = (x + dx , y + dy );
243- if nx < 0
244- || nx >= BOUNDARY
245- || ny < 0
246- || ny >= BOUNDARY
247- || vis . contains (& (nx , ny ))
248- || block . contains (& (nx , ny ))
249- {
250- continue ;
300+
301+ fn dfs (
302+ sx : i64 ,
303+ sy : i64 ,
304+ tx : i64 ,
305+ ty : i64 ,
306+ s : & HashSet <i64 >,
307+ m : i64 ,
308+ vis : & mut HashSet <i64 >,
309+ ) -> bool {
310+ static DIRS : [i64 ; 5 ] = [- 1 , 0 , 1 , 0 , - 1 ];
311+ let key = sx * 1_000_000 + sy ;
312+ vis . insert (key );
313+ if vis . len () as i64 > m {
314+ return true ;
251315 }
252- queue . push_back ((nx , ny ));
253- vis . insert ((nx , ny ));
316+ for k in 0 .. 4 {
317+ let x = sx + DIRS [k ];
318+ let y = sy + DIRS [k + 1 ];
319+ let key = x * 1_000_000 + y ;
320+ if x >= 0 && x < 1_000_000 && y >= 0 && y < 1_000_000 {
321+ if x == tx && y == ty {
322+ return true ;
323+ }
324+ if ! s . contains (& key ) && vis . insert (key ) && dfs (x , y , tx , ty , s , m , vis ) {
325+ return true ;
326+ }
327+ }
328+ }
329+ false
254330 }
255- }
256331
257- vis . len () >= MAX
332+ dfs (
333+ source [0 ] as i64 ,
334+ source [1 ] as i64 ,
335+ target [0 ] as i64 ,
336+ target [1 ] as i64 ,
337+ & s ,
338+ m ,
339+ & mut HashSet :: new (),
340+ ) && dfs (
341+ target [0 ] as i64 ,
342+ target [1 ] as i64 ,
343+ source [0 ] as i64 ,
344+ source [1 ] as i64 ,
345+ & s ,
346+ m ,
347+ & mut HashSet :: new (),
348+ )
349+ }
258350}
259351```
260352
0 commit comments