关于bfs(广度优先搜索算法)和dfs(深度优先搜索算法)--leetcode题:1036. 逃离大迷宫;112. 路径总和;113. 路径总和 II;102. 二叉树的层序遍历;200. 岛屿数量

这篇博客介绍了在LeetCode中的几道题目,包括1036. 逃离大迷宫,112. 路径总和,113. 路径总和 II,102. 二叉树的层序遍历和200. 岛屿数量,分别展示了BFS(广度优先搜索)和DFS(深度优先搜索)的使用。博主通过分析题目的解法,讨论了两种算法在解决路径问题时的策略和代码实现,特别强调了在大迷宫问题中如何避免全网格搜索导致的时间超限问题。
摘要由CSDN通过智能技术生成

leetcode 每日一题

1036. 逃离大迷宫

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

三叶姐姐的题解

为了方便,我们用 ss 代指 sourcesource,用 tt 代指 targettarget,用 nn 来代指 blockedblocked 大小。

整理题意为:在一个足够大的空间里,有少数的障碍物,问两点是否连通。

当两点相隔较远时,常规的 BFS 做法可能会搜完整个棋盘,而棋盘大小为 10^6 * 10^6,会 TLE。

考虑什么情况下两点会不连通?

当两个点中的任意一点被障碍物围住时,两点将无法连通。

一个很容易想到的思路是:从 ss 跑一遍 BFS,然后从 tt 跑一遍 BFS,同时设定一个最大访问点数量 MAX,若从两者出发能够访问的点数量都能超过 MAX,说明

两点均没有被围住,最终必然会联通。

考虑如何敲定 MAX 的取值范围?直观感受,MAX 应该是一个与 blockedblocked 大小相关的数。

但第一反应还是想从单秒计算量上界进行反推,两边 BFS 的复杂度均为 O(max),因此直接设定 MAX = 1e5 应该是比较合适的。

更小的 MAX 需要证明:在给定数量障碍物的前提下,障碍物所能围成的最大面积为多少。

首先,容易想到:任何一条封闭图形的直边都可以通过调整为斜边来围成更大的面积:

image.png

即组成封闭图形的边不可能有直边,同时由于是封闭图形,因此斜边直接必然是单点衔接,而不可能是平行(无法封闭)。

同时,想要达到最大面积,应当尽可能利用边界作为围成图形的某些边。

利用边界所能围成的最大封面图形 可以是「由边界提供两边,障碍物提供一边的三角形」。

如果不是该形状,则可以通过调整障碍物的直边为一条完整的斜边,来组成封闭三角形,围成面积不会变小:

image.png

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-fdVmyNZL-1641894946988)(C:\Users\Admin\AppData\Roaming\Typora\typora-user-images\image-20220111105615014.png)]

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.contai
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值