递归、回溯、DFS、BFS

递归

递归三要素:目的,停止条件,传递条件。

做递归思考三步:

  1. 递归的函数要干什么?

  • 函数作用是判断传入的两个树是否镜像。

  • 输入:TreeNode left, TreeNode right

  • 输出:是:true,不是:false

  1. 递归停止的条件是什么?

  • 左节点和右节点都为空 -> 倒底了都长得一样 ->true

  • 左节点为空的时候右节点不为空,或反之 -> 长得不一样-> false

  • 左右节点值不相等 -> 长得不一样 -> false

  1. 从某层到下一层的关系是什么?

  • 要想两棵树镜像,那么一棵树左边的左边要和二棵树右边的右边镜像,一棵树左边的右边要和二棵树右边的左边镜像

  • 调用递归函数传入左左和右右

  • 调用递归函数传入左右和右左

  • 只有左左和右右镜像且左右和右左镜像的时候,我们才能说这两棵树是镜像的

  1. 调用递归函数,我们想知道它的左右孩子是否镜像,传入的值是root的左孩子和右孩子。这之前记得判个root==null。

回溯

46.全排列(中等)

51.N皇后(困难)

解决一个回溯问题,实际上就是一个决策树的遍历过程。你只需要思考 3 个问题:

1、路径:也就是已经做出的选择。

2、选择列表:也就是你当前可以做的选择。

3、结束条件:也就是到达决策树底层,无法再做选择的条件。

其核心就是 for 循环里面的递归,在递归调用之前「做选择」,在递归调用之后「撤销选择」,特别简单。

写 backtrack 函数时,需要维护走过的「路径」和当前可以做的「选择列表」,当触发「结束条件」时,将「路径」记入结果集。

其实想想看,回溯算法和动态规划是不是有点像呢?我们在动态规划系列文章中多次强调,动态规划的三个需要明确的点就是「状态」「选择」和「base case」,是不是就对应着走过的「路径」,当前的「选择列表」和「结束条件」?

某种程度上说,动态规划的暴力求解阶段就是回溯算法。只是有的问题具有重叠子问题性质,可以用 dp table 或者备忘录优化,将递归树大幅剪枝,这就变成了动态规划。而今天的两个问题,都没有重叠子问题,也就是回溯算法问题了,复杂度非常高是不可避免的。

DFS

BFS

猜你喜欢

转载自blog.csdn.net/qq_31941921/article/details/121736490