解决递归问题的三部曲

时间:2021-07-22 18:59:07

递归就是程序反复调用自身,这说明它每一级的功能是一样的,因此我们只需要关注一级递归的解决过程即可

我们在解决递归问题时,需要关心的主要是以下三点:

  1. 整个递归的终止条件。
  2. 一级递归需要做什么?
  3. 应该返回给上一级的返回值。

因此,也就有了我们解递归题的三部曲:

  1. 找整个递归的终止条件:递归应该在什么时候结束?
  2. 找返回值:应该给上一级返回什么信息?
  3. 本级递归应该做什么:在这一级递归中,应该完成什么任务?

例1:求二叉树的最大深度

题目很简单,求二叉树的最大深度,那么直接套递归解题三部曲模版:

  1. 找终止条件。 什么情况下递归结束?当然是树为空的时候,此时树的深度为0,递归就结束了。
  2. 找返回值。 应该返回什么?题目求的是树的最大深度,我们需要从每一级得到的信息自然是当前这一级对应的树的最大深度,因此我们的返回值应该是当前树的最大深度,这一步可以结合第三步来看。
  3. 本级递归应该做什么。 此时就三个节点:root、root->left、root->right,其中根据第二步,root->left和root->right分别记录的是root的左右子树的最大深度。那么本级递归应该做什么就很明确了,自然就是在root的左右子树中选择较大的一个,再加上1就是以root为根的子树的最大深度了,然后再返回这个深度即可。

利用递归解决上题的c++代码如下:

class Solution {
public:
    int maxDepth(TreeNode* root) {
        if (root == NULL)
            return 0;
        int leftDepth = maxDepth(root->left);
        int rightDepth = maxDepth(root->right);
        return (leftDepth > rightDepth ? leftDepth : rightDepth) + 1;
    }
};

例2:两两交换链表中的节点

直接套用三部曲模版:

  1. 找终止条件。 什么情况下递归终止?没有能够交换的节点时,递归终止。因此当链表只剩一个节点或者没有节点的时候,自然递归就终止了。
  2. 找返回值。 我们希望向上一级递归返回什么信息?由于我们的目的是两两交换链表中相邻的节点,因此自然希望交换给上一级递归的是已经完成交换处理,即已经处理好的链表。
  3. 本级递归应该做什么。 结合第二步,由于只考虑本级递归,所以这个链表在我们眼里其实也就三个节点:head、head->next、已处理完的链表部分。而本级递归的任务也就是交换这3个节点中的前两个节点。

利用递归解决上述问题的c++代码如下:

class Solution {
public:
    ListNode* swapPairs(ListNode* head) {
        if (head == NULL || head->next == NULL)
        {
            return head;
        }
        ListNode* next = head->next;
        head->next = swapPairs(next->next);
        next->next = head;
        return next;
    }
};

一些可以利用三部曲解决的题

Leetcode 101. 对称二叉树

Leetcode 111. 二叉树的最小深度

Leetcode 226. 翻转二叉树

Leetcode 617. 合并二叉树

Leetcode 654. 最大二叉树

Leetcode 83. 删除排序链表中的重复元素

Leetcode 206. 翻转链表

参考自:刘宇麟博客