In a 1 million by 1 million grid, the coordinates of each grid square are (x, y)
.
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.
Constraints:
0 <= blocked.length <= 200
blocked[i].length == 2
0 <= blocked[i][j] < 10^6
source.length == target.length == 2
0 <= source[i][j], target[i][j] < 10^6
source != target
這道題說是有一個一百萬乘以一百萬大小的格子,有個起始坐標 source 和一個終點坐標 target,還給了一個黑名單 blocked,說是上面的點都不能經過,現在問能否從起點到達終點。首先這道題是一道 Hard 題目,要給予充分的尊重,如果你以為這是簡單的迷宮遍歷問題的話,那就大錯特錯了,為啥呢,注意看一下格子的大小,一百萬乘以一百萬,分分鍾讓你記錄遍歷過位置的集合爆棧,這里由於迷宮過於龐大,不一定能直接遍歷到終點。其實這道題的解法挺難想的,要從黑名單的長度下手,題目中限定了黑名單的大小不超過 200,那么來思考用 200 個點能多能封閉多大的空間,如下所示:
0th _________________________
|O O O O O O O X
|O O O O O O X
|O O O O O X
|O O O O X
.O O O X
.O O X
.O X
200th |X
最多能封閉 19900 個點,那么就是說若當前能夠遍歷到 20000 個點,則說明很大機會可以到達終點。當然極端情況下,終點可能被四個黑名單的上的點猶如圍棋圍殺般的包圍着,所以說還需要反着遍歷一般,從終點遍歷點,若能在 20000 步內到達,或者達到了 20000 步,都返回 true,否則返回 false。這里可以用 BFS 來做,由於 visited 集合可能會保存 20000 個點,為了提高效率,可以將二維坐標 encode 成為一個數字,這里用橫坐標乘以一百萬再加上縱坐標,記得要用長整型以免整型溢出。所以這里的 visited 集合可用一個 HashSet,初始時將所有的黑名單 blocked 上的點加進去。然后進行兩次 BFS 遍歷,分別從起點到終點,和從終點到起點,若兩次都返回 true,則整個返回 true,否則返回 false。在 BFS 子函數中,就是經典的 BFS 寫法沒太大的區別,唯一的不同就是用一個變量 cnt 來記錄當前走過的點的個數,當到達了 20000 個,直接返回 true 即可,參見代碼如下:
class Solution {
public:
bool isEscapePossible(vector<vector<int>>& blocked, vector<int>& source, vector<int>& target) {
unordered_set<long> visited;
for (auto &a : blocked) visited.insert(a[0] * 1e6 + a[1]);
return helper(visited, source, target) && helper(visited, target, source);
}
bool helper(unordered_set<long> visited, vector<int>& source, vector<int>& target) {
int N = 1e6, cnt = 0;
vector<vector<int>> dirs{{-1, 0}, {0, 1}, {1, 0}, {0, -1}};
queue<vector<int>> q;
q.push(source);
visited.insert((long)source[0] * N + source[1]);
while (!q.empty()) {
auto t = q.front(); q.pop();
if (t == target) return true;
for (auto &dir : dirs) {
int x = t[0] + dir[0], y = t[1] + dir[1];
if (x < 0 || x >= N || y < 0 || y >= N || visited.count((long)x * N + y)) continue;
visited.insert((long)x * N + y);
q.push({x, y});
if (++cnt == 20000) return true;
}
}
return false;
}
};
Github 同步地址:
https://github.com/grandyang/leetcode/issues/1036
參考資料:
https://leetcode.com/problems/escape-a-large-maze/
https://leetcode.com/problems/escape-a-large-maze/discuss/282860/C%2B%2B-Limited-BFS-28-ms