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 ...
随机推荐
- C#字符类型
C#字符串类型采用Unicode字符集,一个Unicode标准字符长度位16位,它允许用单个编码方案表示世界上使用的所有字符. 字符类型表示位char. 关于字符的转义:C#也可以使用字符转义,用 ...
- [机器学习]Generalized Linear Model
最近一直在回顾linear regression model和logistic regression model,但对其中的一些问题都很疑惑不解,知道我看到广义线性模型即Generalized Lin ...
- AngularJS 1.4对动画系统进行了彻底的重构
分享 <关于我> 分享 [中文纪录片]互联网时代 http://pan.baidu.com/s/1qWkJfcS 分享 <HTML开发MacOSAp ...
- Openssl - Static libraries (w32, mingw) 以及对Qt静态编译时的设置
Openssl static libraries created for Windows 32bit using MinGW compiler Compiled with: ./Con ...
- 逆向工程mybatis-geneator.xml
<?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration ...
- Qt 之 样式表的使用——样式选择器(上下篇,很详细)
http://blog.csdn.net/goforwardtostep/article/details/60884870 http://blog.csdn.net/goforwardtostep/a ...
- Spring与IoC
控制反转(IOC,Inversion of Control),是一个概念,是一种思想. 指将传统上由程序代码直接操控的对象调用权交给容器,通过容器来实现对象的装配和管理.控制反转就是对对象控制权的转移 ...
- 如何使用Vue.js来搭建一个后台管理系统
目录 使用的技术 基础但不好版 1.初始化项目 2.实现初始页内容自定义 3.使用路由 原始代码 自建页面 修改路由 4.测试路由跳转 补充 子路由版 嵌套router-view 定义子路由 修改菜单 ...
- devexpress GridView按条件给行号上色
private void gridView1_CustomDrawCell(object sender, DevExpress.XtraGrid.Views.Base.RowCellCustomDra ...
- python三大主流web框架之Django安装、项目搭建
这一篇我们将迎来python强大的web框架Django,相信大家都已经不陌生,本篇将介绍Django的安装及基础项目搭建,大神略过~ Django是需要我们手动pip安装的,首先我们来安装Djang ...