什么时候用

  1. 题目中暗示了一个或多个解,并且要求我们详尽地列举出每一个解的内容时,一定要想到 DFS、想到递归回溯。
  2. 题目经分析后,可以转化为树形逻辑模型求解。

为什么这样用

递归与回溯的过程,本身就是穷举的过程。题目中要求我们列举每一个解的内容,解从哪来?解是基于穷举思想、对搜索树进行恰当的剪枝后得来的。

这里需要大家注意到另一种问法:不问解的内容,只问解的个数。这类问题往往不用 DFS 来解,而是用动态规划(我们后面会学)。这里,大家先记下这个辨析,对以后做题会有帮助。

**

怎么用

一个模型——树形逻辑模型;两个要点——递归式和递归边界。
树形逻辑模型的构建,关键在于找“坑位”,一个坑位就对应树中的一层,每一层的处理逻辑往往是一样的,这个逻辑就是递归式的内容。至于递归边界,要么在题目中约束得非常清楚、要么默认为“坑位”数量的边界。
用伪代码总结一下编码形式,大部分的解题都复合一下特征:

  1. function xxx(入参) {
  2. 前期的变量定义、缓存等准备工作
  3. // 定义路径栈
  4. const path = []
  5. // 进入 dfs
  6. dfs(起点)
  7. // 定义 dfs
  8. dfs(递归参数) {
  9. if(到达了递归边界) {
  10. 结合题意处理边界逻辑,往往和 path 内容有关
  11. return
  12. }
  13. // 注意这里也可能不是 for,视题意决定
  14. for(遍历坑位的可选值) {
  15. path.push(当前选中值)
  16. 处理坑位本身的相关逻辑
  17. path.pop()
  18. }
  19. }
  20. }