BFS使用场景
连通块问题(Connected Component)
- 通过一个点找到图中连通的所有点
- 非递归的方式找所有方案
分层遍历(Level Order Traversal)
- 图的层序遍历
- 简单图最短路径(Simple Graph Shortest Path)
- 简单图
- 没有方向
- 没有权重
- 两点之间最多只有一条边
- 一个点没有一条边直接连着自己
- 如果图中存在环,则同一个节点可能重复进入队列
- 重复BFS没有意义
- 对于连通块问题,不可能带来新的节点
- 对于最短路问题,不可能带来最短的路径
- 使用哈希表去重
- C++:unordered_map/unordered_set
拓扑排序(Topological Sorting)
- 求任意拓扑序
- 求是否有拓扑序
- 求字典序最小的拓扑序
- 求是否唯一拓扑序
拓扑排序不是传统的排序算法
一个图可能存在多个拓扑序(Topological Order),也可能不存在任何拓扑序
1.统计每个点的入度
2.将每个入度为0的点放入队列(Queue)中作为起始点
3.不断从队列中拿出一个点,去掉这个点的所有连边(指向其他点的边),其他点的相应入度-1
4.一旦发现新的入度为0的点,丢回队列中
BFS算法
BFS通用模板
step 1:初始化
把初始节点放到queue里,如果有多个就都放进去
并标记初始节点的距离为0,记录在distance的map里
distance有两个作用,一个是判断是否已经访问过,二是记录离起点的距离
step 2:不断访问队列
while循环+每次pop队列中的一个点出来
step 3:拓扑相邻节点
pop出的节点的相邻节点,加入队列并在distance中存储距离
137 Clone Graph克隆图
将整个算法分解为三个步骤
1.找到所有点
2.复制所有点
3.复制所有边
一旦入队就要马上访问标记,否则,会有元素重复入列
120 Word Ladder单词接龙
step1:构造dict,必须加入end,可以加入start
step2:记录最短路线长度,起始长度为1
到下一层(不是当前层)的长度
当前层有size个元素
step3:得到下一步的单词
如果下一层的词为尾词,直接返回当前到下一层(不是当前层)的长度
加入下一层,为后面BFS做准备
不能实现首尾接龙,返回0
step3:得到下一步的单词
枚举当前替换字母
枚举替换位置
step4:返回替换后的字符串
如果字母替换后的的单词存在于dict,加入nextWords
step4:返回替换后的字符串
在s中,把位置index的字母替换成c,返回替换后的字符串
433 Number of Islands
矩阵坐标变换数组
deltaX,deltaY
是否在界内:isInBound/isValid
1.逐行逐列进行遍历
2.如果找到一个1,岛屿数量增1
3.把所有跟这个1相连的1都找出来,所有这些相连的1代表一个岛
4.回到步骤1继续遍历
需要定义一个class,表示坐标系中的一个点
定义四个方向的偏移量
特殊情况处理
记录某点是否被BFS过(如果之前BFS过,不应再次被BTS)
遍历矩阵中的每一个点
如果为海洋,无需BFS
如果该点已经被BFS,无需做冗余遍历,重复计算
611 Knight Shortest Path
矩阵坐标变换数组
deltaX,deltaY
是否在界内:isInBound/isValid
8个方向的偏移量
遍历8个不同的方向
新坐标点
如果之前已经到达过词典,不可能通过再次BFS找到最短路径,还会造成死循环
不能到达,返回-1
如果一个点越界或者为障碍物,返回falsse,否则true
值1表示障碍物,返回false
616 Course Schedule II(问是否存在拓扑排序)
图+有依赖关系+有向+无环=>拓扑排序
构建图,代表(先修课->多个后修课)的映射
图的初始化,每个先修课->空后修课
1.统计每个点的入度,并构造图
2.将每个入度为0的点进入队列中作为起始点
记录已修课程的数量
记录拓扑顺序
3.不断从队列中拿出一个点,去掉这个点的所有连边(指向其他点的边),其他点的相应入度-1
当前点的邻居的入度减1,表示每个后修课的一门先修课已经完成
4.一旦发现新的入度为0的点,丢回队列中
表示一门后修课的所有先修课已经完成,可以被修了
127 Topological Sorting 拓扑排序(求任意一个拓扑排序)
同上
605 Sequence Reconstruction(问拓扑排序是否唯一)
queue的长度>1,说明结果不唯一
892 Ailen Dictionary 外星人字典(求字典序最小的拓扑排序)
如果数据不合理,graph为空,返回空字符串
合理则进行拓扑排序
合理判断:
存放(字母->右面的多个字母)的映射关系
生成所有的点,每个点的后缀点暂时为空
生成所有的边,找到一个点之后的点,并建立连接
如果输入["abc","ab"],"abc"出现在"ab"前面,不合法,返回NULL
拓扑排序:
1.统计每个点的入度
2.将每个入度为0的点放入队列中作为起始节点
要求:这里可能有多个有效的字母顺序,返回以正常字典顺序看来最小的
所以这里要heapify,从所有可以出队的元素中,先出对字典比较小的元素
记录拓扑顺序(外星人字典排序)
3.不断从队列中拿出一个点,去掉这个点的所有连边(指向其他点的边)
其他点的相应的入度-1
当前点的邻居的入度减1
4.一旦发现新的入度为0的点,丢回队列中
统计每个点的入度:
统计每个点的入度,如果一个点的入度为0,那么这个点依然存在于dict中,对应入度为0
初始化所有点的入度为0
所有邻居的入度加1