第31-32天学习笔记——DFS/BFS

文章讲述了深度优先搜索(DFS)和广度优先搜索(BFS)在解决LeetCode中的岛屿问题(如695岛屿、面积计算、周长、数量等)中的应用,介绍了统一的模板方法,包括初始化、遍历策略、终止条件和空间时间复杂度分析。
摘要由CSDN通过智能技术生成
  • DFS / BFS
    • 深度优先搜索DFS
      • “ DFS以LeetCode、695岛屿题为模板进行解决 ”
      • LeetCode 200、岛屿数量
        • 最好按照695题的模板来写,统一成一个模板
        • 先初始化一个二维数组(初始化为0,代表当前网格没有被访问,1代表当前网格被访问过),循环遍历当前位置的上、下、左、右四个方向访问网格中的元素,如果发现新位置是陆地,并且没有被标记过,递归搜索新的位置(绿色的位置周边都已经被搜索过了,所以来到上面的1的位置,上面的1的位置周边也已经搜索过了,就来到上面的1的右边位置......)

      • LeetCode 695、岛屿的最大面积(模板题,可以记录这个模板作为DFS模板,其中第2种模板形式可以参考2023Q1A-机器人活动区域的DFS解法)
        • 这道题需要设置递归终止条件,因为我们是要比较到每次搜索完得到的面积们的最大值
        • 这里相比前一道题的改进在于不需要设置mark矩阵了,当我们搜索到当前位置时,发现当前位置为1,即可将其转换为0,即可防止后续继续遍历这个位置
        • 递归的终止条件:越界或者当前格子的值为0
        • 时间复杂度:O(n×m),其中 n 和 m 分别为矩阵的行数和列数。深度优先搜索过程中,每一个点至多只会被标记一次。
        • 空间复杂度:O(n×m),其中 n 和 m 分别为矩阵的行数和列数。主要为深度优先搜索的栈的开销。
      • LeetCode 463、岛屿的周长
        • 和上一道题的区别在于发现当前位置为1,即可将其转换为其他的数字(比如2),如果发现遍历的当前格子是0或者越界(说明之前的格子和现在的格子是20接壤),那就说明此时的周长+1,如果发现遍历的当前格子是2接壤(说明之前的格子和现在的格子是22接壤),那说明此时没有周长变化

        • 时间复杂度:O(n×m),其中 n 和 m 分别为矩阵的行数和列数。深度优先搜索过程中,每一个点至多只会被标记一次。
        • 空间复杂度:O(n×m),其中 n 和 m 分别为矩阵的行数和列数。主要为深度优先搜索的栈的开销。
      • LeetCode 1020、飞地的数量
        • 同样的模板
        • 如果是飞地,那么肯定有格子1在边缘位置
          • 即if ((i == 0 or j == 0 or i == (m - 1) or j == (n - 1)) and grid[i][j] == 1) 时才执行DFS
        • 用DFS将飞地的格子置为0
        • 然后在遍历一遍grid,统计1的数目即为不能飞地的格子数量
      • LeetCode 130、被围绕的区域
        • 就是飞地题换了个说法,还是695的模板
        • 利用两个 for 循环,遍历矩阵中的一些特殊的单元格,将它们赋值为 N
        • 特殊的单元格:必然是从边界处开始的
        • 递归终止条件:board[i][j] == X ,不需要继续搜索下去 # board[i][j] == N ,这个格子已经被访问过,不需要继续搜索下去
        • 否则说明当前单元格是 O,最后需要保留下来的那种 # 将当前单元格置为 N ,避免其它格子 dfs 过程中又把它加入到计算中
      • 【DFS/BFS】美团2023秋招-小美的字符串变换 K(岛屿模板题)
        • 需要完成两个任务
        • 1、找到所有可以摆列的方式,需要满足x*y=n,假设其中x为小的,那么可以枚举1到k(k*k=n,不需要枚举到n),找到所有的枚举方式。这里需要分别对x行y列型和x列y行型进行计算结果,取两种情况的最小值作为最终结果
        • 2、每一个具体的枚举,通过DFS或者BFS的方式,找到其中的联通块数量。这个和岛屿数量是一样的模板。具体实现上标记每个位置是否访问,然后从一个方块如果未访问,那么联通块+1然后向四周搜索拓展、标记。
      • 【DFS/BFS】Shein2023秋招提前批-删点成林(树DFS模板题)
        • 本题看似要求删除,实际上是需要计算从给定的节点x出发,各个方向上的连通块大小。因此用常规的DFS或BFS就可以完成。
        • 1、构建邻接表
          • 利用哈希表neighbor_table = defaultdict(list), 如果a和b具有连接关系,则a的邻接节点中包含b,b的邻接节点包含a
        • 2、构建答案列表,储存删除x后得到的各个连通块的大小,即计算以x为起始节点,各个方向上的连通块的大小
        • 3、构建检查集合,储存已经检查过的节点,由于题目没有说明节点的编号一定是从1到n# 故此处使用哈希集合而不是列表
        • 4、遍历x的所有邻接节点node,从这些邻接节点出发进行DFS搜索
        • 5、在DFS中,遍历当前节点cur_node的所有邻接节点nxt_node,如果nxt_node尚未被检查过,则可以继续进行DFS搜索
      • 【DFS】广联达2023秋招-迷宫(树DFS模板题)
        • 该题目重要的是理解题意
        • 本题其实是求以u为根节点的子树中的叶子节点的数目。
        • 令ans[u]为以u为根节点的子树中的叶子节点的数目,显然ans[u] = ans[v1] + ans[v2] + ans[vk],其中v1, v2, ..., vk为u的所有的子节点。而当u没有节点时,ans[u] = 1。我们可以直接通过一次DFS预处理出ans数组,对于每次查询直接输出答案即可,时间复杂度为O(n)。
        • 解题模板和上一道题类似,需要用到哈希表+DFS,关键在于设置了叶子节点数的dict进行存储,key是node, value是该node的叶子节点数目
      • 【DFS/BFS】2023Q1A-机器人活动区域(岛屿模板题)
        • 注意,本题和LC695. 岛屿的最大面积几乎完全一致,均需要计算最大连通块的面积。唯一的区别在于,本题的连通性需要通过两个数值之差的绝对值来进行判断。
        • 因此,在近邻点是否能够进行进一步DFS/BFS判断的时候,其相关的条件语句条件应该修改为
      • 【DFS/BFS】2023B-战场索敌(岛屿模板题)
        • 属于岛屿类的DFS,直接套用模板即可
        • 找到一个"."或"E",并且这个"."或"E"从未被搜索过:那么可以进行DFS的搜索
      • 【DFS/BFS】2023B-陷阱方格(难题)
        • 本题是一道非常有意思的题目,显然路径的搜索过程可以用DFS/BFS来完成。问题在于如何判断方格是不可达方格和陷阱方格。
        • 我选用了DFS来做,要注意DFS的入口是起点 / 终点,而不是像之前的模板一样遍历所有位置
        • 不可达方格的判断
          • 先考虑相对直观的不可达方格的判断。
          • 我们从起点到终点进行DFS/BFS(注意搜索方向只有向上或向右两个方向),将能够到达的方格在检查数组check_list1中标记为True。搜索完成后,check_list1中所有不为墙壁的False数量,即为不可达方格的数量。

          • 显然上述做法只能够算出不可达方格的数量,因为陷阱方格在搜索过程中是可以到达的。
        • 逆向路径的概念
          • 在判断陷阱方格之前,需要构建一个逆向路径的概念。
          • 如果从某个点(i, j)出发(这个点不一定是起点),只历经向右和向上最终到达终点,那么相对应的,从终点出发也可以只历经向左和向下最终到达该点(i, j),这条路径我们称之为原路径的逆向路径。

          • 很容易证明,如果某条路径存在,那么其逆向路径也一定存在。
        • 陷阱方格的判断
          • 陷阱方格的判断需要借助逆向路径的概念来完成。假设一个方格(i, j)是陷阱方格,它应该满足以下两个要求:
            • 1. 从起点出发,能够到达(i, j)。即从(0, 0)到(i, j)的路径存在。
            • 2. 从(i, j)出发,不能够到达终点(n-1, m-1)。即从(i, j)出发到终点(n-1, m-1)的路径不存在。
          • 上述第一个条件其实非常容易满足。在不可达方格判断中,check_list1中标记为True的点,就是从起点出发能够到达的点。
          • 对于上述的第二个条件,我们可以用逆向路径的概念来描述:
            • 从终点(n-1, m-1)出发到点(i, j)的逆向路径不存在。
          • 因此对于第二个条件,我们可以从终点到起点进行逆向路径的DFS/BFS(注意搜索方向只有向左或向下两个方向),能够到达的位置在检查数组check_list2中标记为True。搜索完成后,check_list2中所有不为墙壁的值为False的点,即为从终点出发的逆向路径无法到达的点。

          • 在check_list1中值为True,在check_list2中值为False的点(且不为墙壁),即是满足上述两个条件的点,也就是陷阱方格。统计满足条件的方格数量即可。
        • 其他特殊处理
          • 至此,本题的分析已经大体完成,我们需要做两次DFS/BFS搜索
            • 第一次从起点出发往终点搜寻,方向只有向上和向右
            • 第二次从终点出发往起点搜寻,方向只有向下和向左
          • 不管是BFS过程还是DFS过程,和常规的搜索过程无异。
          • 另外,考虑到在计算checkList中值的时候需要排除掉墙壁,我们可以在墙壁的初始化时,就把checkList1和checkList2中墙壁所对应的点标记为True,这样可以免去最后一步计数时的繁琐判断。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值