DFS框架
DFS顾名思义是种搜索算法,深度优先,而回溯是DFS过程中的必备操作,因为
- 假如你是搜索一个解:达到这个深度无法找到搜索目标你就需要回溯换条路找解,
- 假如你搜索的是多个解:要么你剪枝你就需要回溯,要么找到一个解需要回溯去找另外的解
回溯过程中需要标记,怎么做标记呢?我们需要栈(递归,也就是函数调用自身自然而然形成栈)
下面是通用的框架:
void DFS(i)
{
1. 标记i
2. 做些事情:比如输出或者return等等
3. 每个i邻接点j:if(未标记||剪枝) DFS(j)
}
我这里的邻接点要放开来想,树和图的邻接点很好想就很直接。那假如是迷宫那就是上下左右,假如N皇后当前行的每一列,假如是生成子集就是当前字符选和不选,思维要扩展
标记i和判断是否标记,这种一般用于类似于图结构,因为不同的点可能拥有相同的邻接点,回溯回来可能会再次相遇
void DFS(i)
{
1. 做些事情:比如输出或者return等等
2. 每个i邻接点j: if(剪枝) DFS(j)
}
而类似于树的就不需要标记,因为回溯过程中直接扔掉,之后不会再见面了。上面的N皇后和生成子集就是用的这个,道理很简单,因为他们的解空间是棵树,所以不用标记啦
个人愚见
BFS框架
广度优先,需要用栈
void BFS()
{
初始化并标记某些入队
while (队列不空) {
1. 队头出队
2. 做些事情:比如输出或者return等等
3. 每个邻接点:if(未标记) {入队;标记;}
}
}
类似DFS,树的就不需要标记。
void BFS()
{
初始化某些入队
while (队列不空) {
1. 队头出队
2. 做些事情:比如输出或者return等等
3. 每个邻接点:入队
}
}
DFS和BFS框架的题目,只要看出本质就能按照框架写出,简单的题其实不要想太多,框架一上就ok
裸的很多很多
104. 二叉树的最大深度
107. 二叉树的层次遍历 II
…
扫描二维码关注公众号,回复:
10497185 查看本文章
需要建图
5354. 通知所有员工所需的时间
…
需要用些高级的数据结构
407. 接雨水 II
…