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 ...
随机推荐
- windows qt 使用c++ posix接口编写多线程程序(真神奇)good
一.多线程是多任务处理的一种特殊形式,多任务处理允许让电脑同时运行两个或两个以上的程序.一般情况下,两种类型的多任务处理:基于进程和基于线程.基于进程的多任务处理是程序的并发执行.基于线程的多任务处理 ...
- 转一个git的命令
Git远程操作详解 Git有很多优势,其中之一就是远程操作非常简便.本文详细介绍5个Git命令,它们的概念和用法,理解了这些内容,你就会完全掌握Git远程操作. git clone git rem ...
- JVM底层实现与总结
一.类加载器 1.BootstrapClassLoader(启动类加载器) 它主要负责加载%JAVA_HOME%/jre/lib,-Xbootclasspath参数指定的路径以及%JAVA_HOME% ...
- Django之用户认证auth模块使用
Auth认证模块 执行数据库迁移的那两条命令时,即使我们没有建表,django是不是也会创建好多张表?我们创建之后去看一下里面的一个叫auth_user表,既然是表,那肯定应该有对应的操作改表的方法 ...
- JS数据结构第四篇 --- 栈
一.什么是数据结构栈 在数据结构中有一个栈结构,在内存空间中也有一个栈空间,这两个”栈“是两个不同的概念.这篇我们说的是数据结构中的栈.栈是一种特殊的线性表,特殊性在哪?就是只能在栈顶进行操作,往栈顶 ...
- Spark学习之路(十四)—— Spark Streaming 基本操作
一.案例引入 这里先引入一个基本的案例来演示流的创建:获取指定端口上的数据并进行词频统计.项目依赖和代码实现如下: <dependency> <groupId>org.apac ...
- Django生成PDF显示在网页上以及解决中文显示乱码的问题
项目地址:https://github.com/PythonerKK/django-generate-pdf/tree/master 这个demo实现了通过用户输入自己的个人信息生成一份简历pdf,来 ...
- canvas实现有递增动画的环形进度条
哈?标题不知道啥意思? 老规矩,直接看图! 效果如下: 高清大图! 码农多年,老眼昏花,动图看不清?!那就看静态截图!!! 不同分值效果如下: 看完了卖家秀,我们来看产品的制作过程吧 ...
- 下一代工业通信—TSN(时间敏感网络),工业物联网的助推器
随着工业物联网(IIoT)的兴起和工业4.0的提出,越来越多的设计师.工程师和最终用户关注TSN(Time-Sensitive Networking,时间敏感网络).TSN为以太网提供确定性性能,本质 ...
- python初识(3)
bool 字符串 for循环 bool 数字非零全都是True 字符串非空全都是True 字符串 索引 从0开始 0 切片选取 [x:y] 左闭右开区间 [x:y:z] 选取x到y之间 每隔z选取一次 ...