DFS & 回溯
理论知识点参见回溯算法
分割等和子集
子集or组合
从一个包含m个元素的集合中挑选出n个元素(0≤n≤m)形成一个子集。一个子集又可以称为一个组合。如果两个子集(组合)的元素完全相同只是顺序不同,那么它们可以看作同一个子集(组合)。 子集和组合定义是相同的
排列
从一个包含m个元素的集合中挑选出n个元素(0≤n≤m)并按照某种顺序形成一个排列。m等于n的排列又称为全排列。如果两个排列的元素完全相同只是顺序不同,那么它们就是两个不同的排列。也就是说,排列与元素的顺序相关,这一点与组合不同。
有重复数字的,先排序,这样就知道当前选择的是否和上一次选择的一样与否
分割字符串
棋盘问题
棋盘问题
二维矩阵搜索问题
对于二位矩阵中搜索问题。首先明确搜索的起点,然后是回溯的每一层开始都去判断当前是否可行,判断可行需要判断以下几点:
- 是否已经到达路径终点
- 当前位置是否越界,判断
i j
- 当前位置是否已经走过一遍, 通常借助used数组来判断
- 当前位置是否还可行
进行以上几点判断后,说明当前位置正确,可以继续往下走,然后就从四个方向继续往下搜索
79. 单词搜索 不明确知道起点的
搜索问题
路径问题
路径问题主要是 二叉树 或者 图 中找某个点到达某个点 的全部路径 or 最短路径等
6059. 检查是否有合法括号字符串路径 路径加状态记忆
记忆化搜索问题
记忆化搜索问题一般涉及到子问题,然后用memo将子问题保存下来。一般也可以采用dp来实现
总结
BFS: 对于解决最短或者最少问题较有效,而且寻找深度小,但缺点是内存消耗大(需要开队列来存储状态
DFS:对于解决遍历和求所有问题有效,对于问题搜索深度小的时候处理速度较快。然后在深度很大的情况下效率不高
DFS优点:
- 内存开销较小,每次只维护一个节点
- 能处理子节点较多或者树层过深的问题(相比BFS)
- 可以用来解决联通性问题(是否有解)
DFS缺点:
- 只能寻找有解但无法找到最优解(寻找最优解需要遍历所有路径,然后比较得到最优解)
Tips
组合 or 子集问题 元素是没有顺序关系的。所以对于重复问题,需要先排序,然后采用以下任意一种方式去重:
- 在每一层,初始化一个空set,然后遍历元素时,判断是否已经在集合中了,如果不在,则添加进去。然后向下一层搜索。如果已经在集合中了,则continue。 对于此种方式,也是需要排序的!!因为不排序的话,对于 4,1,4会出现[4,1] [1, 4]这两种相同的集合or组合
- 因为是排好序的,所以直接采用
if i > start and nums[i] == nums[i-1] :continue
这种方式达到去重目的。
对于要提前返回的,可判断
self.backtrack()
,然后在该函数内部进行判断,进行剪纸返回False,表示当前路行不通。然后再去遍历当前节点下的所有可选值,最后返回值记录
2021年11月22日 | 子集和组合的概念是一样的,只不过子集可以是空集,但组合不行,这是唯一的区别 | 47、22、131 |
2021年11月26日 | 棋盘问题、矩阵搜索问题。只找一条路径的问题,记得每次dfs()都返回 | 51、37 |
ㅤ | 矩阵搜索的问题,一般每一层都有上下左右四条路径可以选择。然后需要注意是进去下一层前就判断条件,还是进去后统一判断。 | 79、剑指13 |
2022年2月4日 | 399,329,79,37, 89,47, 39,40,216,90,22, 131 | ㅤ |