【力扣算法】掌握套路你就赢了-半小时学会重建二叉树(前+中、中+后)

本文详细介绍了如何根据二叉树的前序和中序遍历,或者中序和后序遍历序列来重建二叉树。通过递归的basecase和辅助函数,分别展示了两种情况下的重建过程,并提供了相应的代码实现,强调了关键步骤和区间划分的重要性。
摘要由CSDN通过智能技术生成

1 什么是重建二叉树

直接看力扣题
105. 从前序与中序遍历序列构造二叉树
在这里插入图片描述
106 从中序与后序遍历序列构造二叉树
在这里插入图片描述

综上所述,重建二叉树其实就是根据前+中或中+后这两种遍历后的结果将我们原来的二叉树形式恢复出来。
我们复习一下二叉树的几种遍历
有二叉树如下所示
在这里插入图片描述

前序:根 —》 左 —》 右 的顺序打印
ABDHKECFIGJ
中序:左 —》 根 —》 右 的顺序打印
HKDBEAIFCGJ
后序:左 —》 右 —》 根 的顺序打印
KHDEBIFJGCA

2 分析-以前序+中序为例

假设我们知道了前序数组preOrder为
ABDHKECFIGJ
中序数组inOrder为
HKDBEAIFCGJ

0、假设辅助函数rebuild能够重建二叉树

TreeNode* rebuild(vector<int>& preOrder/*前序数组*/int preBegin/*前序开始*/int preEnd/*前序结束*/, vector<int>& inOrder/*中序数组*/int inBegin/*中序开始*/int inEnd/*中序结束*/);

注1:使用递归的basecase:preBegin > preEnd就返回nullptr
注2:下面操作全在辅助函数内进行
1、我们能够通过前序数组第一个值new一个根结点

TreeNode* root = new TreeNode(preOrder[0]);

2、前序告诉我们根结点的val为A,我们可以找到中序中A的索引
在这里插入图片描述

3、此时在中序数组中inRootPos左侧为树的左子树,右侧为右子树,同样可以把前序数组preOrder分为左右两部分
在这里插入图片描述

4、对左子树部分重建二叉树
root->left = rebuild(前序数组,前序开始, 前序结束, 中序数组, 中序开始, 中序结束);
int leftSize = inRootPos- inBegin;
root->left = rebuild(preOrder, preBeagin + 1, leftSize + preBeagin, inOrder, inBegin, inRootPos- 1); 此处范围看上图3
重建后结果如下所示(下一次的重建范围)
在这里插入图片描述
5、对右子树部分重建二叉树
root->right = rebuild(前序数组,前序开始, 前序结束, 中序数组, 中序开始, 中序结束);
root->right = rebuild(preOrder, leftSize + preBeagin + 1, preEnd, inOrder, inRootPos + 1, inEnd); 看图3
重建后结果如下所示(下一次的重建范围)
在这里插入图片描述

3 框架以及注意部分

代码框架-适用于前+中 中+后:
修改部分
前+中 :

//1、我们能够通过前序数组第一个值new一个根结点
        int RootVal = preOrder[preBeagin];
int leftSize = inRootPos- inBegin;
// 4对左子树重建
        root->left = rebuild(preOrder, preBeagin + 1, leftSize + preBeagin, inOrder, inBegin, inRootPos- 1);
        // 5对右子树重建
        root->right = rebuild(preOrder, leftSize + preBeagin + 1, preEnd, inOrder, inRootPos + 1, inEnd);

代码实现:

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return build(preorder, 0, preorder.size() - 1, inorder, 0, inorder.size() - 1);
    }
	//辅助函数
    TreeNode* rebuild(vector<int>& preOrder, int preBeagin, int preEnd, vector<int>& inOrder, int inBegin, int inEnd)
    {
        //base case
        if (preBeagin > preEnd)
        {
            return nullptr;
        }
        //1、我们能够通过前序数组第一个值new一个根结点
        int RootVal = preOrder[preBeagin];
        TreeNode* root= new TreeNode(RootVal);
        //2、找到中序遍历的根的位置
        int inRootPos = -1; 
        for (int i = inBegin; i <= inEnd; i++)
        {
            if(inorder[i] == RootVal)
            {
                inCur = i;
                break;
            }
        }

        int leftSize = inRootPos- inBegin;
        // 4对左子树重建
        NewHead->left = rebuild(preOrder, preBeagin + 1, leftSize + preBeagin, inOrder, inBegin, inRootPos- 1);
        // 5对右子树重建
        NewHead->right = rebuild(preOrder, leftSize + preBeagin + 1, preEnd, inOrder, inRootPos + 1, inEnd);
        return NewHead;
    }
};

中+后:
修改部分:

//1、寻找根结点
        int rootVal = postOrder[posEnd];
//对子节点进行递归
        int leftSize = inPos - inBegin;
        // 4
        root->left = rebuild(inOrder, inBegin, inPos - 1, postOrder, posBegin, leftSize + posBegin - 1);
        //区间很重要,一定要画图理解!!
        // 5
        root->right = rebuild(inOrder, inPos + 1, inEnd, postOrder, leftSize + posBegin, posEnd - 1);

代码实现:

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        return build(inorder, 0, inorder.size() - 1, postorder, 0, postorder.size() - 1);
    }
    TreeNode* rebuild(vector<int>& inOrder, int inBegin, int inEnd, vector<int>& postOrder, int posBegin, int posEnd)
    {
        //base case
        if (posBegin > posEnd)
        {
            return nullptr;
        }
        //1、寻找根结点
        int rootVal = postOrder[posEnd];
        TreeNode* root = new TreeNode(rootVal);
        //找到在中序数组的根的索引
        int inPos = -1;
        for (int j = inBegin; j <= inEnd; j++)
        {
            if (rootVal == inOrder[j])
            {
                inPos = j;
                break;
            }
        }
        //对子节点进行递归
        int leftSize = inPos - inBegin;
        // 4
        root->left = rebuild(inOrder, inBegin, inPos - 1, postOrder, posBegin, leftSize + posBegin - 1);
        //区间很重要,一定要画图理解!!
        // 5
        root->right = rebuild(inOrder, inPos + 1, inEnd, postOrder, leftSize + posBegin, posEnd - 1);
        return root;
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值