二叉树递归法解题思路篇

二叉树解题的思维模式分两类:

1、是否可以通过遍历一遍二叉树得到答案?如果可以,用一个 traverse 函数配合外部变量来实现,这叫「遍历」的思维模式。

2、是否可以定义一个递归函数,通过子问题(子树)的答案推导出原问题的答案?如果可以,写出这个递归函数的定义,并充分利用这个函数的返回值,这叫「分解问题」的思维模式。

无论使用哪种思维模式,你都需要思考:

如果单独抽出一个二叉树节点,它需要做什么事情?需要在什么时候(前/中/后序位置)做?其他的节点不用你操心,递归函数会帮你在所有节点上执行相同的操作。

本文主要针对第二个思维模式进行解题思路的总结:

例题:力扣第 226 题「 翻转二叉树

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    TreeNode* invertTree(TreeNode* root) {

    }
};

 解题思维模式:

1.尝试给invertTree函数赋予一个定义,可以解决这道题。(并且确定函数的参数和返回值)

定义:将以root为根的这颗二叉树翻转,然后返回二叉树的根节点

2.思考递归函数的终止条件是什么?

例如:if(root==NULL) reutrn root;

3.然后思考,对于某一个二叉树节点 x 执行 invertTree(x),你能利用这个递归函数的定义做点啥?(也叫做单层递归的逻辑)

我可以用 invertTree(x->left) 先把 x 的左子树翻转,再用 invertTree(x->right) 把 x 的右子树翻转,最后把 x 的左右子树交换,这恰好完成了以 x 为根的整棵二叉树的翻转,即完成了 invertTree(x) 的定义。

那么下面就是解题代码:

// 定义:将以 root 为根的这棵二叉树翻转,返回翻转后的二叉树的根节点
TreeNode* invertTree(TreeNode* root) {
    if (root == nullptr) {
        return nullptr;
    }
    // 利用函数定义,先翻转左右子树
    TreeNode* left = invertTree(root->left);
    TreeNode* right = invertTree(root->right);

    // 然后交换左右子节点
    root->left = right;
    root->right = left;

    // 和定义逻辑自恰:以 root 为根的这棵二叉树已经被翻转,返回 root
    return root;
}

二、例题:力扣第 116 题「 填充每个二叉树节点的右侧指针

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode() : val(0), left(nullptr), right(nullptr) {}
 *     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
 *     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
 * };
 */
class Solution {
public:
    void flatten(TreeNode* root) {

    }
};

 解题思维模式:

1.尝试给flatten函数赋予一个定义,可以解决这道题。(并且确定函数的参数和返回值)

定义:输入节点root,然后root为根的二叉树就会被拉平成一条链表

2.思考递归函数的终止条件是什么?

例如:if(root==NULL) reutrn;

3.有了这个函数定义,如何按题目要求把一棵树拉平成一条链表?

对于一个节点 x,可以执行以下流程:

1、先利用 flatten(x->left) 和 flatten(x->right) 将 x 的左右子树拉平。

2、将 x 的右子树接到左子树下方,然后将整个左子树作为右子树。

3、先将左子树拉平,再将右子树拉平。将左子树置空,将右子树指向原来的左子树,再将原来的右子树接到现在的右子树下面。

那么下面就是解题代码:

// 定义:将以 root 为根的树拉平为链表
void flatten(TreeNode* root) {
    // base case
    if (root == nullptr) return;

    // 利用定义,把左右子树拉平
    flatten(root->left);
    flatten(root->right);

    /**** 后序遍历位置 ****/
    // 1、左右子树已经被拉平成一条链表
    TreeNode* left = root->left;
    TreeNode* right = root->right;

    // 2、将左子树作为右子树
    root->left = nullptr;
    root->right = left;

    // 3、将原先的右子树接到当前右子树的末端
    TreeNode* p = root;
    while (p->right != nullptr) {
        p = p->right;
    }
    p->right = right;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值