leetcode 1036. Escape a Large Maze 解法 python

本文深入探讨了一种在大规模网格中寻找从起点到终点路径的算法。通过分析障碍物分布特性,提出了一种基于步数限制的解决方案,有效避免了在无限网格中搜索的效率问题。文章详细解释了算法原理,并提供了Python实现代码。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一.问题描述

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:

  1. 0 <= blocked.length <= 200
  2. blocked[i].length == 2
  3. 0 <= blocked[i][j] < 10^6
  4. source.length == target.length == 2
  5. 0 <= source[i][j], target[i][j] < 10^6
  6. source != target

二.解题思路

这道题首先想到的是深度优先搜索,即以一个点开始,往上下左右四个方向扩散找路。但是我们需要注意一下整个迷宫的空间范围,可以看到maze的空间范围是10^6*10^6,感觉不做任何处理这样子相当于要遍历整个空间,会惨遭tle,最后实现之后果不其然,惨遭tle。

注意到blocked的长度最大只有200,比10^6小的多,重心应该在blocked上

首先我们先明确一点,如果被挡住的区域是x格,我从source点往四处扩散,用一个step变量记录我的步数,每走到一个格我就+一步,如果我走了x+1步,那么这个source点定然没有被围住出不去。

因为如果source点被围住出不去了了,那么blocked的所有点可以和边界围成一个闭区域,假设这个闭区域的空间为x,那么从source点往外遍历最多只能走x步,如果我遍历能走到x+1步,说明这个区域没有被围住,有地方可以出去

然后我们再对target也来一次这样的遍历,如果source和target都没有被围住,那么两者能通

最大的迭代次数就是围住区域的最大值乘2

而我们这道题重点就在最大的围起来的闭区域会是多少

很多人会认为是长和宽相等的时候围住的区域最大,这在连续的问题上是这样的

但是我们的空间是离散的

答案是B*(B-1)/2,B是blocked的长度

最大的围住的区域是当blocked以45度的方向排成一个斜线和边界线构成一个闭区域的时候

证明:

当两个cell水平排列的时候,我们可以把一个cell往上或往下下移一个,这样子还是一个闭区域,但是多了一个格子的空间

当两个cell垂直排列的时候,我们可以把一个cell往左或往右移一个,这样子还是一个闭区域,但是多了一个格子的空间

同时要注意新一个变量来跟踪已经遍历过的地方,不然会死循环

还有把blocked最好转变成set,这样查询一个变量是否在set里面的时候是O(1)时间复杂度

之后看到其他高效算法会更新

更新:

也可以不用围住的区域大小,用level来做剪枝的判断,不过这样用在bfs上才行,dfs还是围住的区域才行

level指的是第几条对角线

level=1 指的是[0,0]

level2 是[1,0]和[0,1]连成的对角线,因为每次向下或者向上扩散一个level,所以最大step是len(blocked)*2

更多leetcode算法题解法请关注我的专栏leetcode算法从零到结束或关注我

欢迎大家一起套路一起刷题一起ac

三.源码

class Solution:
    def isEscapePossible(self, blocked: List[List[int]], source: List[int], target: List[int]) -> bool:
        bkset=set(map(tuple,blocked))
        flag=set()
        return self.findtarget(bkset,flag,tuple(source),tuple(target),0) and \
               self.findtarget(bkset,flag,tuple(target),tuple(source),0)
    
    def findtarget(self,bkset,flag,source,target,step):
        if step>=20000 or source==target:
            return True
        if source[0]<0 or source[0]>=1000000 or source[1]<0 or source[1]>=1000000 or source in flag or source in bkset:
            return False
        flag.add(source)
        return self.findtarget(bkset,flag,(source[0]+1,source[1]),target,step+1) or \
               self.findtarget(bkset,flag,(source[0]-1,source[1]),target,step+1) or \
               self.findtarget(bkset,flag,(source[0],source[1]+1),target,step+1) or \
               self.findtarget(bkset,flag,(source[0],source[1]-1),target,step+1)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值