DFS、BFS
数据结构:二叉树,图,二维矩阵
图的遍历
-
深度优先搜索(DFS)
检查图的连通性和无环性、关节点
-
广度优先搜索(BFS)
检查图的连通性和无环性、求两个给定顶点间 边的数量 最少的路径
图的存储
邻接矩阵
适合于边稠密图
邻接表
适用于边数较少的稀疏图
拓扑排序
有向无环图(DAG,directed acyclic graph)
拓扑排序:对于图 G 中的任意一条有向边 (u,v),u 在排列中都出现在 v 的前面。
m个顶点,n条边,时间复杂度O(m+n)
邻接矩阵邻接表:时间复杂度O(n+e)
算法步骤
搜索入度为零的顶点,加入队列
当队列不空时
- 取队首元素u,加入答案
- 将u的相邻顶点入度减1,若减为0,加入队列
若答案包括n个顶点,得到拓扑排序,否则有环
210. 课程表 II
现在你总共有 numCourses 门课需要选,记为 0 到 numCourses - 1。给你一个数组 prerequisites ,其中 prerequisites[i] = [ai, bi] ,表示在选修课程 ai 前 必须 先选修 bi 。
例如,想要学习课程 0 ,你需要先完成课程 1 ,我们用一个匹配来表示:[0,1] 。返回你为了学完所有课程所安排的学习顺序。可能会有多个正确的顺序,你只要返回 任意一种 就可以了。如果不可能完成所有课程,返回 一个空数组 。
class Solution { |
访问标记设置:可以通过额外的访问标记数组进行记录,或者通过修改原数组数值表明已经访问过
深度优先搜索
深度优先搜索(depth-first search, DFS)在搜索到一个新的节点时,立即堆该新节点进行遍历;深度优先搜索用先入后出的栈来实现,也可以通过递归实现。
//采用邻接表存储,递归实现 |
695. 岛屿的最大面积
递归写法:先判断是否满足条件,再进行递归,可以在访问节点时设置访问标记
class Solution { |
栈实现
在入队时设置访问标记,如果出队时设置访问标记,可能导致多次入队,2、3出队列时分别导致4进入队列。
class Solution { |
广度优先搜索
广度优先搜索(breadth-first search,BFS)逐层进行遍历,使用先入先出的队列进行遍历。可用于处理无权最短路径。
初始化:根元素入队,设置访问标记
当队列不为空的时候
- 求队列长度$s_i$
- 从队列中取$s_i$个元素,进行下一轮扩展
- 节点未被访问过,节点入队,设置访问标记
//邻接表存储 |
$$
时间复杂度:O(n+m),其中n为定点数,m为边数\
空间复杂度:O(n),队列开销
$$
回溯
回溯法(backtracking)是优先搜索的一种特殊情况,常用于需要记录节点状态的深度优先搜索。排列、组合、选择类问题使用回溯法。回溯法可以对图的总状态进行修改,而非每次遍历时新建一个图来储存状态。
深度优先搜索:[修改当前节点状态]->[递归子节点]
回溯:[修改当前节点状态]->[递归子节点]->[回改当前节点状态]
选择k个数字构成一个排列
选择若干数字组成一个目标和target
对全部数字进行排列
方法一:回溯
class Solution { |
方法二:位枚举
class Solution { |
47. 全排列 II
给定一个可包含重复数字的序列
nums
,按任意顺序 返回所有不重复的全排列。
对于重复的数字要保证在结果中的相对位置一致 |
class Solution { |
934. 最短的桥
在给定的二维二进制数组 A 中,存在两座岛。(岛是由四面相连的 1 形成的一个最大组。)
现在,我们可以将 0 变为 1,以使两座岛连接起来,变成一座岛。
返回必须翻转的 0 的最小数目。(可以保证答案至少是 1 。)
广度优先搜索从一个岛屿出发不断扩展一圈,何时可以找到另外一个岛屿。前提如何保障找到扩展相应第一步时的相应初始位置。
初始时找到一个岛屿的一个点,不断向外扩展,每一层可以找到从这一点向外n步时可以到达的位置。
class Solution { |
130. 被围绕的区域
给你一个 m x n
的矩阵 board
,由若干字符 'X'
和 'O'
,找到所有被 'X'
围绕的区域,并将这些区域里所有的 'O'
用 'X'
填充。
tip1
me: 用一个状态记录四周的O可以连接到的位置
在遍历所有位置,不能被四周连接到的改为‘X’
深度优先搜索
|
tip2
优化???