题目
在一个 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^6106∗106的数组记忆化搜索,会超时,因为太大了.
用dfs递归方法,会出现堆栈太深,而导致报错.
因此选用unordered_set代替1 0 6 ∗ 1 0 6 10^6 * 10^6106∗106的数组进行记忆化搜索,把走过的点都保存下来,防止反复走.
用迭代bfs的方法(queue来实现),取代递归dfs,因为栈太深,会出错.
由于每次保存两个值,用pair来存储x和y
unordered_set对于pair需要手动定义哈希函数,才能使用.
block无需重新一个unordered_set,它可以直接和记忆化搜索的unordered_set进行合并,都是不能走的位置,没必要分两个.
方法一:自定义哈希+BFS迭代
分别从起点到终点
终点到起点
起点或者终点,有一个被封到角落里,就不能到达(返回false)
只要走了n ∗ ( n − 1 ) / 2 n*(n-1)/2n∗(n−1)/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作为起始点,没有被封住 } };