Leetcode:106. 从中序与后序遍历序列构造二叉树、105. 从前序与中序遍历序列构造二叉树(C++)

目录

106. 从中序与后序遍历序列构造二叉树:

问题描述:

 实现代码与解析:

切割法(递归):

原理思路:

索引版本:

105. 从前序与中序遍历序列构造二叉树:

问题描述:

实现代码与解析:

切割法(递归):

原理思路:

索引版本:


106. 从中序与后序遍历序列构造二叉树:

问题描述:

        给定两个整数数组 inorder 和 postorder ,其中 inorder 是二叉树的中序遍历, postorder 是同一棵树的后序遍历,请你构造并返回这颗 二叉树 。

示例 1:

输入:inorder = [9,3,15,20,7], postorder = [9,15,7,20,3]
输出:[3,9,20,null,null,15,7]

示例 2:

输入:inorder = [-1], postorder = [-1]
输出:[-1]

 实现代码与解析:

切割法(递归):

class Solution {
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) 
    {
        //若为空树
        if(postorder.size()==0)
        {
            return NULL;//返回NULL,最后的叶子结点左右子树都为空
        }
        int rootValue=postorder[postorder.size()-1];//后序最后一个元素       
        TreeNode* root=new TreeNode(rootValue);//后序遍历的第一个结点为根结点
        //叶子结点
        if(postorder.size()==1) return root;
        int index;//中序切割点
        //寻找切割点
        for(index=0;index<inorder.size();index++)
        {
            if(inorder[index]==rootValue) break;
        }
        //切割中序数组
        vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
        vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
        postorder.pop_back();//去除后序最后一个元素
        //切割后序数组
        vector<int> leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());
        vector<int> rightPostorder(postorder.begin()+leftInorder.size(),postorder.end());
        root->left=buildTree(leftInorder,leftPostorder);
        root->right=buildTree(rightInorder,rightPostorder);
        return root;
    }
};

原理思路:

        用中序和后序、中序和前序构造二叉树是数据结构中的一种经典题型,如果只是画出二叉树的图像,大家应该是都会的,这里介绍一些如何用代码来还原二叉树。

        1、首先写递归的终止条件,判断后序数组是否为空,若为空,说明该树是空树,直接返回NULL,同时也解决了递归式时有一侧子树为空的空结点可以返回。

//若为空树
if(postorder.size()==0)
{
    return NULL;//返回NULL,最后的叶子结点左右子树都为空
}

        2、判断是否进入到了叶子结点,也就是后序数组只剩下一个数,返回此结点,去掉此代码也是可以的,因为我们前面有了遇到空结点时返回的代码,遇到叶子结点再向下递归一层到空结点返回也是可以的。

//叶子结点
if(postorder.size()==1) return root;

        3、然后我们就记录后序数组最后一个元素来寻找切割点了,把中序数组切割成左中序和右中序,然后再根据左中序大小,将后序数组切成左后序和右后序,注意在切割后序数组前把后序数组最后一个数去掉,因为我们这层已经用过这个结点值了,还有注意切割的左右是开还是闭,切割中序和后序时最好保持统一。

//切割中序数组
vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
postorder.pop_back();//去除后序最后一个元素
//切割后序数组
vector<int> leftPostorder(postorder.begin(),postorder.begin()+leftInorder.size());
vector<int> rightPostorder(postorder.begin()+leftInorder.size(),postorder.end());

        4、递归同时进行结点的连接,左子树传入左中序和左后序,右子树传入右中序和右后序。

root->left=buildTree(leftInorder,leftPostorder);
root->right=buildTree(rightInorder,rightPostorder);

        还有另一种写法,就是每次递归时多传入切割的中序区间的索引,后序区间的索引的参数。这样就不用我们每次递归时在单独创建vector了,减少了空间,不过原理是相同的,下面给出:

索引版本:

class Solution {
private:
    TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& postorder, int postorderBegin, int postorderEnd) 
    {
        if (postorderBegin == postorderEnd) return NULL;
        int rootValue = postorder[postorderEnd - 1];
        TreeNode* root = new TreeNode(rootValue);
        if (postorderEnd - postorderBegin == 1) return root;
        int Index;//中序切割点
        for (Index = inorderBegin; Index < inorderEnd;Index++) 
        {
            if (inorder[Index] == rootValue) break;
        }
        // 切割中序数组
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = Index;
        int rightInorderBegin = Index + 1;
        int rightInorderEnd = inorderEnd;
        // 切割后序数组
        int leftPostorderBegin =  postorderBegin;
        int leftPostorderEnd = postorderBegin + (Index - inorderBegin); 
        int rightPostorderBegin = postorderBegin + (Index - inorderBegin);
        int rightPostorderEnd = postorderEnd - 1; // 去除最后一个元素
        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  postorder, leftPostorderBegin, leftPostorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, postorder, rightPostorderBegin, rightPostorderEnd);
        return root;
    }
public:
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if (inorder.size() == 0 || postorder.size() == 0) return NULL;
        return traversal(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};

105. 从前序与中序遍历序列构造二叉树:

问题描述:

        给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]

实现代码与解析:

切割法(递归):

class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
    {
        if(preorder.size()==0) return NULL;
        int rootValue=preorder[0];
        TreeNode* root=new TreeNode(rootValue);
        //叶子结点
        if(preorder.size()==1) return root;
        int index;//切割点
        for(index=0;index<inorder.size();index++)
        {
            if(rootValue==inorder[index]) break;
        }
        //切割中序数组
        vector<int> leftInorder(inorder.begin(),inorder.begin()+index);
        vector<int> rightInorder(inorder.begin()+index+1,inorder.end());
        //切割前序数组
        preorder.erase(preorder.begin());//去除第一个元素,已经使用过了
        vector<int> leftPreorder(preorder.begin(),preorder.begin()+leftInorder.size());
        vector<int> rightPreorder(preorder.begin()+leftInorder.size(),preorder.end());
        root->left=buildTree(leftPreorder,leftInorder);
        root->right=buildTree(rightPreorder,rightInorder);
        return root;
        
    }
};

原理思路:

        此题与上一题原理相同,就不详细解释了,还是给出索引版本的代码:

索引版本:

class Solution {
private:
        TreeNode* traversal (vector<int>& inorder, int inorderBegin, int inorderEnd, vector<int>& preorder, int preorderBegin, int preorderEnd) {
        if (preorderBegin == preorderEnd) return NULL;
        int rootValue = preorder[preorderBegin]; 
        TreeNode* root = new TreeNode(rootValue);
        if (preorderEnd - preorderBegin == 1) return root;
        int delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) 
        {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;
        // 切割前序数组
        int leftPreorderBegin =  preorderBegin + 1;
        int leftPreorderEnd = preorderBegin + 1 + delimiterIndex - inorderBegin; 
        int rightPreorderBegin = preorderBegin + 1 + (delimiterIndex - inorderBegin);
        int rightPreorderEnd = preorderEnd;
        root->left = traversal(inorder, leftInorderBegin, leftInorderEnd,  preorder, leftPreorderBegin, leftPreorderEnd);
        root->right = traversal(inorder, rightInorderBegin, rightInorderEnd, preorder, rightPreorderBegin, rightPreorderEnd);
        return root;
    }
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) 
    {    
        return traversal(inorder, 0, inorder.size(), preorder, 0, preorder.size());
    }
};
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Cosmoshhhyyy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值