1036. 逃 离 大 迷 宫 \color{red}{1036. 逃离大迷宫} 1036.逃离大迷宫
在一个 10^6 x 10^6 的网格中,每个网格上方格的坐标为 (x, y)
。
现在从源方格 source = [sx, sy]
开始出发,意图赶往目标方格 target = [tx, ty]
。数组 blocked
是封锁的方格列表,其中每个 blocked[i] = [xi, yi]
表示坐标为 (xi, yi)
的方格是禁止通行的。
每次移动,都可以走到网格中在四个方向上相邻的方格,只要该方格 不 在给出的封锁列表 blocked
上。同时,不允许走出网格。
只有在可以通过一系列的移动从源方格 source
到达目标方格 target
时才返回 true
。否则,返回 false
。
数据(关键)约束:
0 <= blocked.length <= 200
解题思路:
- 首先对于这种网格中找路径的问题,一般都是通过搜索算法解题——根据是否要求最短路径,数据量大小等酌情选取DFS或者BFS,以及其他更优的搜索算法…
- 由于这道题的数据量,而且没有要求找一条最短的“逃脱”路径,如果通过BFS逐步扩展的话肯定没机会的;考虑一下DFS,在根据这道题的Hard难度,不难想到使用优化后的DFS算法——最常见的优化就是剪枝优化了(常用剪枝策略有三种:记忆化-相同值从记忆数组中提取结果、最优解判断-如果当前枝差于当前最优剪枝、可行性剪枝-当前枝不可能获得解剪枝)
- 但是这道题应该不是剪枝,而属于距离限制的DFS搜索:由于一个特殊的数据约束,封锁格子最多只有200格,假设这些格子按照斜线排序达到最好封锁效果,类似与如下边,只要DFS到达的点和原点的曼哈顿距离到达一定范围,即肯定冲破封锁。这个范围根据最好的封锁效果(图1)不难得到为blocked.length
- 于是,在DFS达到据原点一定距离的点,或者直接搜索到目标,即表示该节点“free”了
解题代码:
还有很大改进空间:
class Solution {
//封锁格子数量
int len;
//上下左右方向数组
int[][] d;
//保存访问信息
Map<Integer,Set<Integer>> v;
//全局block
int[][] b;
public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {
b=blocked;
len=blocked.length;
d=new int[][]{
{
-1,0},{
1,0},{
0,-1},{
0,1}};
//访问原节点
v=new HashMap<>();
Set<Integer> sou=new HashSet<Integer>();
sou.add(source[1]);
v.put(source[0],sou);
//判断原节点是否free
if(dfs(source,source,target)){
v=new HashMap<>();
Set<Integer> tar=new HashSet<Integer>();
tar.add(target[1]);
v.put(target[0],tar);
//判断目标节点是否free
if(dfs(target,target,source))
return true;
}
return false;
}
public boolean dfs(int[] cur,int[] o,int[] t){
//如果超过范围,或者到达目标返回true
if((Math.abs(cur[0]-o[0])+Math.abs(cur[1]-o[1]))>=len||(cur[0]==t[0]&&cur[1]==t[1])){
return true;
}
else{
for(int i=0;i<4;i++){
int mx=cur[0]+d[i][0];
int my=cur[1]+d[i][1];
if(mx<0||mx>=1000000||my<0||my>=1000000||judge(mx,my)){
continue;
}
else{
Set<Integer> j=v.get(mx);
if(j==null||!j.contains(my)){
if(j==null){
j=new HashSet<Integer>();
}
j.add(my);
v.put(mx,j);
if(dfs(new int[]{
mx,my},o,t))
return true;
}
else{
continue;
}
}
}
}
return false;
}
//判断是否是blocked
public boolean judge(int x,int y){
for(int i=0;i<len;i++){
if(b[i][0]==x&&b[i][1]==y)
return true;
}
return false;
}
}
结尾
题目来源:力扣(LeetCode) 链接:https://leetcode-cn.com/problems
⭐️关注作者,带你刷题,从简单的算法题了解最常用的算法技能(寒假每日一题)
⭐️关注作者刷题——简单到进阶,让你不知不觉成为无情的刷题机器,有问题请私信