树——二叉树学习(2)

重构二叉树

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

解题过程

身为小白的我,这段时间一直想要搞明白这个重构过程(其实是放假了休息了好几天,懒可以战胜一切),结果智商不够是硬伤,第一次递归能想明白,再纯靠大脑想第二次递归就宕机了,所以我痛定思痛,放弃了知其所以然。

如何在已知前序遍历和中序遍历的条件下重建二叉树,需要知道两点:1、在中序遍历找到根可以很快的区分出当前区间的左子树和右子树;2、前序遍历第一个元素为根元素,在构建TreeNode时候val就是用的前序遍历根元素的值。

重建二叉树的编写过程(强行记住先)

  1. 快速寻找中序遍历中根的位置(用hash表来存中序遍历中元素的位置下表很方便),构建hash表来完成:map<int,int> hash;
  2. 因为会经常用到前序遍历和中序遍历数组,所以使用vector来建立全局变量:vector<int>preorder,inorder;
  3. 重建二叉树函数中:先对全局变量赋值,然后在hash表中存储数据,最后递归调用函数dsf。
  4. 编写递归调用函数。递归调用的函数的输入有4个:前序遍历的左边界、右边界;中序遍历的左边界、有边界(递归赋值)
  5. 在递归调用函数中,如果pl>pr(左边界的坐标大于有边界的坐标)返回NULL值(return nullptr);
  6. 在递归函数中,最后、最重要的:需要完成对每个节点的树结构体进行定义,并分别定义当前节点的根、左子树、右子树。
  7. 当前节点的树的根就是当前前序遍历区间的左边界值:auto root=new TreeNode(preorder[pl]);
  8. 寻找当且节点的根在中序遍历的位置:int k=hash[root->val];那么左子树的长度就是k-il;右子树的长度就是ir-k
  9. 当前节点的树的左子树就是:auto left=dsf();root->left=left;==>左子树的指针地址就是左子树的dsf函数地址,使用auto来自动生成变量类型 auto left=dsf(左子树的:前序左边界,右边界,中序左边界,右边界)                                        其中左子树前序左边界为pl+1,前序右边界为pl+1+k-il-1,中序左边界为il,中序右边界为k-1
  10. 当前节点的树的右子树就是:auto right=dsf() ;root->right=right;==>右子树的指针地址就是右子树的dsf函数点至,使用auto来自动生成变量类型 auto right=dsf(右子树的:前序左边界,右边界,中序左边界,右边界)                             其中右子树前序左边界为 pl+k-il+1,前序右边界为pr,中序左边界为k+1,中序右边界为ir
  11. 返回当前节点树:return root;

这就是一个重建二叉树的全部程序的编写,其中除了过程的记忆,还要记住几个左子树和右子树的递归参数。

利用hash表来求长度减少了每次使用for循环来寻找位置,不用hash表可以用这个

int k=0;
for(int i=0;i<inorder.size();i++)
{
    if(inorder[i]==preorder[pl])
    {
        k=i;
        break;
    }

}
//k或者valinInorder就是中序遍历里面根的位置

hash表 还需要学习。c++好难,但还是要坚持下去。

 

 

 

 

整个题的程序就是下面这个。记住它,然后编写它

/**
 * Definition for binary tree
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
public:
    map<int,int> hash;
    vector<int>preorder,inorder;
    TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) 
    {
        preorder=pre,inorder=vin;
        for(int i=0;i<inorder.size();i++)
            hash[inorder[i]]=i;
        return dsf(0,preorder.size()-1,0,inorder.size()-1);
    }
    TreeNode* dsf(int pl,int pr,int il,int ir)
    {
        if(pl>pr) return nullptr;
        auto root=new TreeNode(preorder[pl]);
        int k=hash[root->val];
        auto left=dsf(pl+1,pl+1+k-il-1,il,k-1);
        auto right=dsf(pl+k-il+1,pr,k+1,ir);
        root->left=left;
        root->right=right;
        return root;
    }
};

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值