1036. Escape a Large Maze
Problem Setting¶
In a 1 million by 1 million grid, the coordinates of each grid square are (x, y)
with 0 <= x, y < 10^6
.
We start at the source
square and want to reach the target
square. Each move, we can walk to a 4-directionally adjacent square in the grid that isn't in the given list of blocked
squares.
Return true
if and only if it is possible to reach the target square through a sequence of moves
Link for Problem: leetcode
Example 1:¶
Input: blocked = [[0,1],[1,0]], source = [0,0], target = [0,2]
Output: false
Explanation: The target square is inaccessible starting from the source square, because we can't walk outside the grid.
Example 2:¶
Input: blocked = [], source = [0,0], target = [999999,999999]
Output: true
Explanation:
Because there are no blocked cells, it's possible to reach the target square.
import collections
from typing import List, Set, Dict, Tuple, Optional
class Solution:
def isEscapePossible(self, blocked: List[List[int]], source: List[int], target: List[int]) -> bool:
blocked = {(x, y) for x, y in blocked}
source = tuple(source)
target = tuple(target)
def bfs(s, e):
visited = {s}
frontier = collections.deque([s])
while frontier:
sz = len(frontier)
if sz > len(blocked) * 4:
return 1
for i in range(sz):
r, c = frontier.popleft()
if (r, c) == e:
return 2
for newr, newc in (r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1):
if 0 <= newr < 1000000 and 0 <= newc < 1000000 and (newr, newc) not in blocked and (newr, newc) not in visited:
visited.add((newr, newc))
frontier.append((newr, newc))
return 0
return bfs(source, target) + bfs(target, source) > 1
# Example 1
blocked = [[0,1],[1,0]]; source = [0,0]; target = [0,2]
s = Solution()
s.isEscapePossible(blocked, source, target)
Step-by-step understanding¶
This problem can be solved by using dynamic programming. Overall flow is as blew:
- Initial setting
- Define recursive function
bfs
for dynamic programming - Execute the recursive function from the starting point i.e.,
source
to the end point i.e.target
as well as the other way around i.e., fromtarget
tosource
Initial setting¶
L5-7 convert input arguments into tuple format.
print('Before: ', blocked, source, target)
blocked = {(x, y) for x, y in blocked}
source = tuple(source)
target = tuple(target)
print('After: ', blocked, source, target)
Define dfs
¶
This recursive function explore the 1 million by 1 million grid using DFS (Depth First Search), in which a recursive function goes deeper search areas first until it reaches a sort of the end.
def bfs(s, e):
visited = {s}
frontier = collections.deque([s])
while frontier:
sz = len(frontier)
if sz > len(blocked) * 4:
return 1
for i in range(sz):
r, c = frontier.popleft()
if (r, c) == e:
return 2
for newr, newc in (r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1):
if 0 <= newr < 1000000 and 0 <= newc < 1000000 and (newr, newc) not in blocked and (newr, newc) not in visited:
visited.add((newr, newc))
frontier.append((newr, newc))
return 0
-
visited
keeps tracking where it is already searched. -
frontier
keeps tracking the grid coordinates it needs to check.
s = source; e = target
visited = {s}
frontier = collections.deque([s])
while frontier:
sz = len(frontier)
if sz > len(blocked) * 4:
pass
# return 1
for i in range(sz):
r, c = frontier.popleft()
if (r, c) == e:
pass
# return 2
for newr, newc in (r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1):
if 0 <= newr < 1000000 and 0 <= newc < 1000000 and (newr, newc) not in blocked and (newr, newc) not in visited:
visited.add((newr, newc))
frontier.append((newr, newc))
break
print(visited, frontier, sz, len(blocked))
Check a 4-directionally adjacent square¶
There are 4 different direction that we can move. The if
statement checks the followings:
- the next point is within the grid (make sure that it is not out of indexes.)
- the next point is not in the
blocked
list - the next point is not in the
visited
list
If all three conditions are met, it adds the next points (newr, newc)
to visited
.
Also, it appends the next points are frontier
for newr, newc in (r - 1, c), (r + 1, c), (r, c - 1), (r, c + 1):
if 0 <= newr < 1000000 and 0 <= newc < 1000000 and
(newr, newc) not in blocked and
(newr, newc) not in visited:
visited.add((newr, newc))
frontier.append((newr, newc))
Check if one of the frontiers reaches the end e
¶
In the for loop, it takes one coordinate (r, c)
from frontier
and check if it matches with e
, the end destination.
for i in range(sz):
r, c = frontier.popleft()
if (r, c) == e:
return 2
Execute dfs
from both source
and target
¶
By executing the dfs
from both source
and target
, if it meets on the same coordinate, it means it is solved.
return bfs(source, target) + bfs(target, source) > 1
Comments
Comments powered by Disqus