Baozi Leetcode solution 1036: Escape a Large Maze
Problem Statement
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.
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.
Note:
0 <= blocked.length <= 200blocked[i].length == 20 <= blocked[i][j] < 10^6source.length == target.length == 20 <= source[i][j], target[i][j] < 10^6source != target
Hints
- If we become stuck, there's either a loop around the source or around the target.
- If there is a loop around say, the source, what is the maximum number of squares it can have?
Problem link
Video Tutorial
You can find the detailed Youtube video tutorial here
国内:B站的视频戳这里
Thought Process
At first, I am puzzled why this problem would be a hard one. It seems simply applying a BFS would get the answer. So here we go.
Brute force, simple BFS
Of course it will hit memory limit because I am allocating a 2-dimensional visited array. Assume boolean is 8 bit -> 1B, 1 Million * 1 Million = 1TB, OMG, immediately using a set instead.
P.S. fun fact, you can use this method to test how much memory leetcode allocate to this problem, you can use binary search and memory is around 300MB
However, this would start hitting Time Limit Exception. Now I begin to notice a few constrains, e.g., the block size is only 200 while the grid is 1M*1M. Simply going from source to target worst case would cause a timeout.
Next thought would be does it help if we sort the block array? While we are doing the BFS, if the block is already larger/smaller than the max/min of the block, we can early stop. However, this won't help if we simply place a block near the target. Also, this would be a nightmare to implement.
Check block loops on source and target
Following the two hints, it would be natural to come up with this idea. Given such huge contrast between the block size (0,200) and the grid size (1M, 1M), all we need to do is to check if there is any loops built by block on source and target b/c if there is a loop, we cannot explore outside of the loop. However, notice if target and source are in the same loop, then we are fine.
There are two ways to early stop this loop checking. One way is to count the BFS steps, the other way is to follow the hints, given 200 blocks, what's the max area it can cover. Given the length 200, Fig 2 in the below graph can result in the largest area. Therefore, we can early terminate the BFS search once we covered more than 19900 blocks. (We can relax this a bit to 20000, doesn't matter)
- Fig 1 area = 100 * 100 = 10000
- Fig 2 area = 1 + 2 + 3 + ... + 199 = (1+199)*199/2 = 19900
- Fig 3 area = 1 * 200 = 200
- Fig 4 area = 790 (2*Pi*R = 100, thus R = 15.92, Pi * R^2 = 790 )

Solutions
Brute force, simple BFS
private final int[] xDirection = {1, 0, -1, 0};
private final int[] yDirection = {0, -1, 0, 1};
private final int ONE_MILLION = 1000000;
public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {
if (blocked == null || source == null || target == null) {
return false;
}
Set<String> blockLookup = this.indexBlockedMatrixToSet(blocked);
int m = ONE_MILLION;
int n = ONE_MILLION;
Set<String> visited = new HashSet<>();
Queue<String> queue = new LinkedList<>();
String sourceString = source[0] + "," + source[1];
queue.offer(sourceString);
visited.add(sourceString);
while (!queue.isEmpty()) {
String[] curBlock = queue.poll().split(",");
int curX = Integer.parseInt(curBlock[0]);
int curY = Integer.parseInt(curBlock[1]);
if (curX == target[0] && curY == target[1]) {
return true;
}
for (int i = 0; i < 4; i++) {
int nextX = curX + xDirection[i];
int nextY = curY + yDirection[i];
if (this.shouldExplore(nextX, nextY, ONE_MILLION, ONE_MILLION, blockLookup, visited)) {
String nextKey = nextX + "," + nextY;
visited.add(nextKey);
queue.offer(nextKey);
}
}
}
return false;
}
private boolean shouldExplore(
int x,
int y,
int row,
int col,
Set<String> blockLookup,
Set<String> visited) {
if (!(x >= 0 && x < row && y >=0 && y < col)) {
return false;
}
String index = x + "," + y;
if (visited.contains(index)) {
return false;
}
if (blockLookup.contains(index)) {
return false;
}
return true;
}
private Set<String> indexBlockedMatrixToSet(int[][] blocked) {
Set<String> lookup = new HashSet<>();
for (int i = 0; i < blocked.length; i++) {
int x = blocked[i][0];
int y = blocked[i][1];
String index = x + "," + y;
lookup.add(index);
}
return lookup;
}
Time Complexity: O(N), N = 1M * 1M, essentially need to cover the entire huge grid
Space Complexity: O(N), N = 1M*1M, essentially all the nodes need to be put to visited set
Check block loops on source and target
private final int[] xDirection = {1, 0, -1, 0};
private final int[] yDirection = {0, -1, 0, 1};
private final int ONE_MILLION = 1000000;
private final int MAX_COUNT_THRESHOLD = 20000;
public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {
if (blocked == null || source == null || target == null) {
return false;
}
Set<String> blockLookup = this.indexBlockedMatrixToSet(blocked);
boolean isSourceLoop = this.isLoopAroundPoint(source, target, blockLookup);
if (isSourceLoop) {
return false;
}
boolean isTargetLoop = this.isLoopAroundPoint(target, source, blockLookup);
if (isTargetLoop) {
return false;
}
return true;
}
private boolean isLoopAroundPoint(int[] source, int[] target, Set<String> blockLookup) {
int count = 0;
Set<String> visited = new HashSet<>();
Queue<String> queue = new LinkedList<>();
String index = source[0] + "," + source[1];
queue.offer(index);
visited.add(index);
while (!queue.isEmpty()) {
String[] curBlock = queue.poll().split(",");
int curX = Integer.parseInt(curBlock[0]);
int curY = Integer.parseInt(curBlock[1]);
// here think about
if (count >= MAX_COUNT_THRESHOLD) {
return false;
}
if (curX == target[0] && curY == target[1]) {
return false;
}
for (int i = 0; i < 4; i++) {
int nextX = curX + xDirection[i];
int nextY = curY + yDirection[i];
if (this.shouldExplore(nextX, nextY, ONE_MILLION, ONE_MILLION, blockLookup, visited)) {
String nextKey = nextX + "," + nextY;
count++;
visited.add(nextKey);
queue.offer(nextKey);
}
}
}
return true;
}
private boolean shouldExplore(
int x,
int y,
int row,
int col,
Set<String> blockLookup,
Set<String> visited) {
if (!(x >= 0 && x < row && y >=0 && y < col)) {
return false;
}
String index = x + "," + y;
if (visited.contains(index)) {
return false;
}
if (blockLookup.contains(index)) {
return false;
}
return true;
}
private Set<String> indexBlockedMatrixToSet(int[][] blocked) {
Set<String> lookup = new HashSet<>();
for (int i = 0; i < blocked.length; i++) {
int x = blocked[i][0];
int y = blocked[i][1];
String index = x + "," + y;
lookup.add(index);
}
return lookup;
}
Time Complexity: O(N), N in terms of block size
Space Complexity: O(N), N in terms of block size
References
Baozi Leetcode solution 1036: Escape a Large Maze的更多相关文章
- [Swift]LeetCode1036.逃离大迷宫 | Escape a Large Maze
In a 1 million by 1 million grid, the coordinates of each grid square are (x, y) with 0 <= x, y & ...
- Baozi Leetcode Solution 205: Isomorphic Strings
Problem Statement Given two strings s and t, determine if they are isomorphic. Two strings are isomo ...
- Baozi Leetcode Solution 290: Word Pattern
Problem Statement Given a pattern and a string str, find if str follows the same pattern. Here follo ...
- leetcode solution cracked tutorial
leetcode solution cracked tutorial problemset https://leetcode.com/problemset/all/ Top Interview Que ...
- 【LeetCode】789. Escape The Ghosts 解题报告(Python & C++)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 【LeetCode】830. Positions of Large Groups 解题报告(Python)
作者: 负雪明烛 id: fuxuemingzhu 个人博客: http://fuxuemingzhu.cn/ 目录 题目描述 题目大意 解题方法 日期 题目地址:https://leetcode.c ...
- 73th LeetCode Weekly Contest Escape The Ghosts
You are playing a simplified Pacman game. You start at the point (0, 0), and your destination is(tar ...
- Leetcode solution 291: Word Pattern II
Problem Statement Given a pattern and a string str, find if str follows the same pattern. Here follo ...
- Leetcode solution 227: Basic Calculator II
Problem Statement Implement a basic calculator to evaluate a simple expression string. The expressio ...
随机推荐
- 毕设(五)ListView
ListView 控件可使用四种不同视图显示项目.通过此控件,可将项目组成带有或不带有列标头的列,并显示伴随的图标和文本. 可使用 ListView 控件将称作 ListItem 对象的列表条目组织成 ...
- Creating a Linux Daemon (service) in Delphi
With the introduction of the Linux target for Delphi, a wide range of possibilities are opened up to ...
- CMake编译Widget UI Qt程序
自从CMake被引入到KDE项目的编译系统中后,CMake的使用者日益增多,Qt也不例外,除了使用QMAKE编译Qt程序外,也可以使用CMake来编译Qt程序,并且CMake在使用上更灵活,特别是大型 ...
- vs中debug的一个小技巧 -- debug时忽略某段代码
#line 这是C#中的预处理命令 Visual Studio 2008 Visual Studio 2005 Visual Studio 2012 #line hidden 指令对调试器隐藏若干连续 ...
- 【UVA - 11624】Fire!
-->Fire! 直接上中文 Descriptions: 乔在迷宫中工作.不幸的是,迷宫的一部分着火了,迷宫的主人没有制定火灾的逃跑计划.请帮助乔逃离迷宫.根据乔在迷宫中的位置以及迷宫的哪个方块 ...
- 使用redis PSUBSCRIBE实现实时任务
PSUBSCRIBE可以监听键的过期事件 1.进行数据库的配置 notify-keyspace-events Ex 2.使用命令监听事件 psubscribe __keyevnet@0__:expi ...
- Mysql事务隔离级别和锁机制
一.Spring支持四种事务隔离级别: 1.ISOLATION_READ_UNCOMMITTED(读未提交):这是事务最低的隔离级别,它充许令外一个事务可以看到这个事务未提交的数据. 2.ISOLAT ...
- TCP/IP 第四、五章
1, 2, 整个arp请求的过程. 3,arp -a 获取arp高速缓存.一般arp高速缓存存活时间20分钟,不完整的表项设置为3分钟.因为机器的ip地址可能发生改变. 4, 5,arp一般是操作系统 ...
- chmod命令用法详解-chmod修改目录权限
chmod用法: 用来修改某个目录或文件的访问权限. 语法: chmod [-cfvR] [--help] [--version] [who] [+ | - | =] [mode] 文件名 例子: ...
- 美化Div的边框
CSS修饰Div边框 大部分时候,Div的边框真的做的太丑了,如果不用很多样式来修饰的话,它永远都是那么的突兀.作为一个后端开发,前端菜鸡,在没有设计和前端开发自己独自做项目的时候常常会遇到Div边框 ...