逃离大迷宫
难度:
标签:
题目描述
代码结果
运行时间: 113 ms, 内存: 23.8 MB
/*
题目思路:
1. 使用广度优先搜索(BFS)来遍历网格。
2. 维护一个队列用于存储当前的探索位置。
3. 使用一个集合来记录已经访问过的节点,避免重复访问。
4. 每次从队列中取出一个位置,检查它的四个邻接位置是否可以移动,如果可以移动且是目标位置,则返回true。
5. 如果队列为空且未找到目标位置,则返回false。
6. 使用Java Stream API对代码进行简化。
*/
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;
public class SolutionStream {
private static final int[][] DIRECTIONS = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};
public boolean isEscapePossible(int[][] blocked, int[] source, int[] target) {
Set<String> blockedSet = Arrays.stream(blocked)
.map(b -> b[0] + "," + b[1])
.collect(Collectors.toSet());
return bfs(blockedSet, source, target) && bfs(blockedSet, target, source);
}
private boolean bfs(Set<String> blockedSet, int[] source, int[] target) {
Set<String> visited = new HashSet<>();
Queue<int[]> queue = new LinkedList<>();
queue.offer(source);
visited.add(source[0] + "," + source[1]);
int maxSteps = blockedSet.size() * blockedSet.size();
int steps = 0;
while (!queue.isEmpty()) {
int[] current = queue.poll();
steps++;
if (steps > maxSteps) return true;
for (int[] dir : DIRECTIONS) {
int x = current[0] + dir[0];
int y = current[1] + dir[1];
if (x < 0 || x >= 1000000 || y < 0 || y >= 1000000) continue;
if (x == target[0] && y == target[1]) return true;
if (!blockedSet.contains(x + "," + y) && visited.add(x + "," + y)) {
queue.offer(new int[]{x, y});
}
}
}
return false;
}
}
解释
方法:
该题解采用了深度优先搜索(DFS)来检查从源点到目标点是否存在一条路径。关键在于处理大量的封锁点,为此,题解中使用了一个计算技巧:基于最坏情况下被封锁的最大区域的大小来设置一个探索限制。当被阻塞的点数量为b时,最坏情况下它们可以封锁的区域为 b*(b-1)/2,即在这个范围内搜索。如果在达到这个区域限制之前就找到了目标点,或者探索的区域达到了这个限制,就认为存在路径。如果在达到限制前未找到路径,则假定被封锁。题解首先从源点开始,尝试到达目标点;然后反过来,从目标点尝试到达源点,两者都必须是可行的,才能最终返回 true。
时间复杂度:
O(b^2)
空间复杂度:
O(b^2)
代码细节讲解
🦆
在题解中提到的计算技巧`最坏情况下被封锁的最大区域的大小为 b*(b-1)/2`是如何得出的?这个计算公式有特定的数学或几何背景吗?
▷🦆
为什么需要从两个方向(源点到目标点和目标点到源点)进行搜索才能确定是否存在通路?单向搜索不足以验证路径存在吗?
▷🦆
题解中使用的深度优先搜索(DFS)为何选择在达到某个计算出的探索限制后停止?这样的停止条件是否可能导致误判路径的存在或不存在?
▷