leetcode
leetcode 951 ~ 1000
逃离大迷宫

逃离大迷宫

难度:

标签:

题目描述

代码结果

运行时间: 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`是如何得出的?这个计算公式有特定的数学或几何背景吗?
这个计算公式基于组合数学中的排列组合概念。假设有b个封锁点,最坏情况下,每个封锁点都能与其他封锁点相连形成一个封闭区域。这可以被视为在b个点中任意选择两个点来形成一条边的场景,其可能的边数是组合数C(b,2),即b*(b-1)/2。这代表如果b个点完全连接,可以最多形成b*(b-1)/2条边。在几何上,这可以视为b个点最多能围成的凸多边形的边数,尽管实际的封锁区域可能形状各异,但这提供了一个理论上的最大可能封锁区域估计。
🦆
为什么需要从两个方向(源点到目标点和目标点到源点)进行搜索才能确定是否存在通路?单向搜索不足以验证路径存在吗?
在一些情况下,单向搜索可能遇到偏差。例如,从源点到目标点可能存在一条通路,但那条路可能是因为搜索算法的特定路径选择而找到的,而实际上从目标点回到源点可能完全不可行。执行双向搜索可以验证路径的双向可达性,确保无论从哪个方向开始,路径都是开放且可行的,从而增加算法对于路径存在的确认的准确性。
🦆
题解中使用的深度优先搜索(DFS)为何选择在达到某个计算出的探索限制后停止?这样的停止条件是否可能导致误判路径的存在或不存在?
设置探索限制是为了避免在大迷宫中进行过度深入无限的搜索,从而减少计算资源的消耗和提高算法效率。这个限制基于最坏情况下的封锁区域大小,是一种启发式的方法。当搜索达到这个限制时,并没有找到目标点,可以合理地推测路径被封锁。然而,这种方法可能会导致误判,特别是在封锁点分布不均或实际可通过的路径非常复杂时。这种情况下,可能存在通路但未被发现,因为搜索被提前终止了。相反,如果实际封锁点较少,这种方法可能较为保守地认为路径存在。

相关问题