leetcode-1036:逃离大迷宫

简介: leetcode-1036:逃离大迷宫

题目

题目链接

在一个 106 x 106 的网格中,每个网格上方格的坐标为 (x, y) 。

现在从源方格 source = [sx, sy] 开始出发,意图赶往目标方格 target = [tx, ty] 。数组 blocked 是封锁的方格列表,其中每个 blocked[i] = [xi, yi] 表示坐标为 (xi, yi) 的方格是禁止通行的。

每次移动,都可以走到网格中在四个方向上相邻的方格,只要该方格 不 在给出的封锁列表 blocked 上。同时,不允许走出网格。

只有在可以通过一系列的移动从源方格 source 到达目标方格 target 时才返回 true。否则,返回 false。

示例 1:

输入:blocked = [[0,1],[1,0]], source = [0,0], target = [0,2]
输出:false
解释:
从源方格无法到达目标方格,因为我们无法在网格中移动。
无法向北或者向东移动是因为方格禁止通行。
无法向南或者向西移动是因为不能走出网格。

示例 2:

输入:blocked = [], source = [0,0], target = [999999,999999]
输出:true
解释:
因为没有方格被封锁,所以一定可以到达目标方格。

解题

此题的特殊性,直接dfs会超时

1 0 6 ∗ 1 0 6 10^6 * 10^6106106的数组记忆化搜索,会超时,因为太大了.

用dfs递归方法,会出现堆栈太深,而导致报错.

因此选用unordered_set代替1 0 6 ∗ 1 0 6 10^6 * 10^6106106的数组进行记忆化搜索,把走过的点都保存下来,防止反复走.

用迭代bfs的方法(queue来实现),取代递归dfs,因为栈太深,会出错.

由于每次保存两个值,用pair来存储x和y

unordered_set对于pair需要手动定义哈希函数,才能使用.

block无需重新一个unordered_set,它可以直接和记忆化搜索的unordered_set进行合并,都是不能走的位置,没必要分两个.

方法一:自定义哈希+BFS迭代

参考链接

分别从起点到终点

终点到起点

起点或者终点,有一个被封到角落里,就不能到达(返回false)

只要走了n ∗ ( n − 1 ) / 2 n*(n-1)/2n(n1)/2,就封不住了.

class Solution {
public:
    static const int BOUND=1000000;
    //定义哈希函数
    struct Myhasher{
        size_t operator()(const pair<int,int>& o)const{
            hash<uint64_t> fn=hash<uint64_t>();
            auto&[x,y]=o;
            return (uint64_t)x<<20|y;
        }
    };
    bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
        if(blocked.size()<2) return true;//小于2个必定封不住
        if(bfs(blocked,source,target)==false) return false;//起点被封住
        else if(bfs(blocked,target,source)==false) return false;//终点被封住
        else return true;
    }
    bool bfs(vector<vector<int>>& blocked,vector<int>&source,vector<int>& target){
        unordered_set<pair<int,int>,Myhasher> set;
        int blockedN=blocked.size();
        int countMax=(blockedN)*(blockedN+1)/2;//走过的格子数超过这个,则没能挡住该出发点
        for(auto& pos:blocked){//把障碍物加入set中,表明这些路不能走
            set.emplace(pos[0],pos[1]);
        }
        queue<pair<int,int>> q;//queue来实现bfs
        vector<vector<int>> dirs={{1,0},{-1,0},{0,1},{0,-1}};
        q.emplace(source[0],source[1]);
        while(!q.empty()&&countMax>0){
            auto [x,y]=q.front();
            q.pop();
            for(int d=0;d<4;d++){
                int nx=x+dirs[d][0];
                int ny=y+dirs[d][1];
                if(nx>=0&&nx<BOUND&&ny>=0&&ny<BOUND&&!set.count({nx,ny})){//没有超出边界并且该格子还能走
                    if(nx==target[0]&&ny==target[1]) return true;
                    set.emplace(nx,ny);//走过的格子标记不能再走
                    --countMax;
                    q.emplace(nx,ny);
                }
            }
        }
        if(countMax>0) return false;//没有超过最大格子数,就不能再走了,说明路被封住了
        return true;//source作为起始点,没有被封住
    }
};


相关文章
|
7月前
|
安全 算法 测试技术
【动态规划】【广度优先】LeetCode2258:逃离火灾
【动态规划】【广度优先】LeetCode2258:逃离火灾
|
7月前
|
安全 算法 测试技术
【动态规划】【广度优先】LeetCode2258:逃离火灾
【动态规划】【广度优先】LeetCode2258:逃离火灾
|
存储
Leetcode-每日一题1210. 穿过迷宫的最少移动次数(BFS)
版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/weixin_46618592/article/details/128890280?spm=1001.2014.3001.5501
118 0
Leetcode-每日一题1210. 穿过迷宫的最少移动次数(BFS)
|
机器学习/深度学习
力扣-1036. 逃离大迷宫
在一个 106 x 106 的网格中,每个网格上方格的坐标为 (x, y) 。 现在从源方格 source = [sx, sy] 开始出发,意图赶往目标方格 target = [tx, ty] 。数组 blocked 是封锁的方格列表,其中每个 blocked[i] = [xi, yi] 表示坐标为 (xi, yi) 的方格是禁止通行的。 每次移动,都可以走到网格中在四个方向上相邻的方格,只要该方格 不 在给出的封锁列表 blocked 上。同时,不允许走出网格。 只有在可以通过一系列的移动从源方格 source 到达目标方格 target 时才返回 true。否则,返回 false。
101 0
力扣-1036. 逃离大迷宫
|
机器学习/深度学习 C++
【力扣·每日一题】1036. 逃离大迷宫 (C++ bfs 思维)
【力扣·每日一题】1036. 逃离大迷宫 (C++ bfs 思维)
97 0
【力扣·每日一题】1036. 逃离大迷宫 (C++ bfs 思维)
|
算法 定位技术 索引
[leetcode/lintcode 题解] 阿里算法面试真题:迷宫
[leetcode/lintcode 题解] 阿里算法面试真题:迷宫
[leetcode/lintcode 题解] 阿里算法面试真题:迷宫
|
3月前
|
Unix Shell Linux
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行
本文提供了几个Linux shell脚本编程问题的解决方案,包括转置文件内容、统计词频、验证有效电话号码和提取文件的第十行,每个问题都给出了至少一种实现方法。
LeetCode刷题 Shell编程四则 | 194. 转置文件 192. 统计词频 193. 有效电话号码 195. 第十行