• leetcode1036. 逃离大迷宫(java)


    题目描述

    难度 - 困难
    leetcode1036. 逃离大迷宫

    在一个 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
    解释:
    因为没有方格被封锁,所以一定可以到达目标方格。

    提示:
    0 <= blocked.length <= 200
    blocked[i].length == 2
    0 <= xi, yi < 10^6
    source.length == target.length == 2
    0 <= sx, sy, tx, ty < 10^6
    source != target
    题目数据保证 source 和 target 不在封锁列表内
    在这里插入图片描述

    BFS + 给定障碍物所能围成的最大面积

    我们用 sss 代指 source,用 ttt 代指 target,用 n 来代指 blocked 大小。
    整理题意为:在一个足够大的空间里,有少数的障碍物,问两点是否连通。
    当两点相隔较远时,常规的 BFS 做法可能会搜完整个棋盘,而棋盘大小为 10^6 * 10^6 ,会 超时。
    考虑什么情况下两点会不连通?
    当两个点中的任意一点被障碍物围住时,两点将无法连通。
    一个很容易想到的思路是:从 s 跑一遍 BFS,然后从 t 跑一遍 BFS,同时设定一个最大访问点数量 MAX,若从两者出发能够访问的点数量都能超过 MAX,说明两点均没有被围住,最终必然会联通。
    考虑如何敲定 MAX 的取值范围?直观感受,MAX 应该是一个与 blocked 大小相关的数。
    但第一反应还是想从单秒计算量上界进行反推,两边 BFS 的复杂度均为 O(max⁡),因此直接设定 MAX = 1e5 应该是比较合适的。
    更小的 MAX 需要证明:在给定数量障碍物的前提下,障碍物所能围成的最大面积为多少。
    首先,容易想到:任何一条封闭图形的直边都可以通过调整为斜边来围成更大的面积:

    即组成封闭图形的边不可能有直边,同时由于是封闭图形,因此斜边直接必然是单点衔接,而不可能是平行(无法封闭)。
    同时,想要达到最大面积,应当尽可能利用边界作为围成图形的某些边。
    利用边界所能围成的最大封面图形 可以是「由边界提供两边,障碍物提供一边的三角形」。
    如果不是该形状,则可以通过调整障碍物的直边为一条完整的斜边,来组成封闭三角形,围成面积不会变小:
    在这里插入图片描述
    即给定 nnn 的情况下,根据「等差数列求和」可知,最大所能围成的面积为 1+2+…+n−1=n∗(n−1)/2 。

    因此如果从 sss 和 ttt 出发,能够访问的点数超过 n∗(n−1)/2 个,那么两点并没有被围住,必然联通。

    代码演示:

    class Solution {
        int EDGE = (int)1e6, MAX = (int)1e5;
        long BASE = 131L;
        Set<Long> set = new HashSet<>();
        int[][] dir = new int[][]{{1,0},{-1,0},{0,1},{0,-1}};
        public boolean isEscapePossible(int[][] blocked, int[] s, int[] t) {
            for (int[] p : blocked) set.add(p[0] * BASE + p[1]);
            int n = blocked.length;
            MAX = n * (n - 1) / 2; // 可直接使用 1e5
            return check(s, t) && check(t, s);
        }
        boolean check(int[] a, int[] b) {
            Set<Long> vis = new HashSet<>();
            Deque<int[]> d = new ArrayDeque<>();
            d.addLast(a);
            vis.add(a[0] * BASE + a[1]);
            while (!d.isEmpty() && vis.size() <= MAX) {
                int[] poll = d.pollFirst();
                int x = poll[0], y = poll[1];
                if (x == b[0] && y == b[1]) return true;
                for (int[] di : dir) {
                    int nx = x + di[0], ny = y + di[1];
                    if (nx < 0 || nx >= EDGE || ny < 0 || ny >= EDGE) continue;
                    long hash = nx * BASE + ny;
                    if (set.contains(hash)) continue;
                    if (vis.contains(hash)) continue;
                    d.addLast(new int[]{nx, ny});
                    vis.add(hash);
                }
            }
            return vis.size() > MAX;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
  • 相关阅读:
    Shell 编程实践
    ZYNQ PS与PL通信之DMA
    java使用libreOffice预览word,ppt,txt等文档
    当我只有一个代理,我该如何从内网搭建一个docker环境
    错误消息 “Column ‘device_id‘ in field list is ambiguous“
    查看、校验、归档…带你掌握openGauss账本数据库
    leetcode - 456. 132 Pattern
    高级架构师_Redis_第2章_数据类型与底层数据结构
    python opencv实现图片清晰度增强
    java毕业设计项目ssm+mysql实现投票管理系统|问卷[包运行成功]
  • 原文地址:https://blog.csdn.net/SP_1024/article/details/133364476