剑指 Offer 07. 重建二叉树

题目:

输入某二叉树的前序遍历和中序遍历的结果,请重建该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如,给出

前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
返回如下的二叉树:

    3
   / \
  9  20
    /  \
   15   7
 

来源:力扣(LeetCode)   链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof
 

解法:

1.递归

根据前序序列找到根结点,再根据中序序列找到包括此根结点的全部结点,不断重复此过程递归找到所有结点。

struct TreeNode {
      int val;
      TreeNode *left;
      TreeNode *right; 
  };
class Solution {
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
          
        if(preorder.size()<=0||inorder.size()<=0||preorder.size()!=inorder.size()) return NULL;
        int h1=0,t1=preorder.size()-1,h2=0,t2=inorder.size()-1;  //先序、序的前后。
        return bt(preorder,inorder,h1,t1,h2,t2);
    }
    TreeNode* bt(vector<int>& preorder, vector<int>& inorder,int h1,int t1,int h2,int t2)
    {

        //h1,t1是前序的root的子节点们;h2,t2是中序的root的子节点们
        TreeNode *root = new TreeNode;
        int i,leftL,rightL;
        //找根结点
        root->val = preorder[h1];
        //分开左右子树

        for(i = h2; i < t2; i++ )
        {
            if(inorder[i]==root->val)break;
        }  
        leftL = i-h2;
        rightL = t2-i;
        if(leftL>0)
        {
            //左子树存在  找左子树的所有结点构成书
            root->left = bt(preorder,inorder,h1+1,t1-rightL,h2,t2-rightL-1);

        }else root->left = NULL;
        if(rightL>0)
        {
            //右子树存在 找右子树的所有结点构成书
            root->right = bt(preorder,inorder,h1+leftL+1,t1,h2+leftL+1,t2);
        }else root->right = NULL;

        return root;
    }
/*
迭代版,效率高
在先序遍历中,前后紧邻的两个节点a和b,在树中的位置有三种情况
1、b是a的左子树节点(父子关系),对应a有左子树
2、b是a的右子树节点(父子关系),对应a没有左子树,但有右子树
3、b是a的某个有右子树的祖父节点,对应a既没有左子树,也没有右子树
因为在前序遍历中,a的祖父节点和祖父节点的左子树绝不可能在a的后面,

在中序遍历中,前后紧邻的两个节点a和b,在树中的位置有两种情况:
1、b是a的右子树中的最左侧节点,对应a有右子树(在a右子树只有一个节点的情况下,退化为b是a的右节点)
2、a是b的左子树中的最右侧节点,对应a没有右子树(在b的左子树只有一个节点的情况下,退化为a是b的左节点)

作者:adsk47
链接:https://leetcode-cn.com/problems/zhong-jian-er-cha-shu-lcof/solution/cliang-chong-jie-fa-di-gui-die-dai-by-ad-wx6w/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
*/
    //时间最快的解法
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.empty()) return nullptr;
        stack<TreeNode*> s;
        TreeNode *root=new TreeNode(preorder[0]);  //根节点
        TreeNode *cur=root;  //正在确定位置的节点
        for(int i=1,j=0;i<preorder.size();i++) {
            //有左子树的情况,一直沿左子树深入,并将沿途节点放入栈中
            if (cur->val != inorder[j]) {  //inorder[j]代表最左节点(去除已经确定左子树的节点)
                cur->left = new TreeNode(preorder[i]);
                s.emplace(cur);
                cur = cur->left;
            } else {  //没有左子树的情况
                j++;
                while (!s.empty() && s.top()->val == inorder[j]) {  //栈顶是其父节点,判断有无右子树
                    cur = s.top();  //没有右子树,就追溯到有右节点的祖父节点
                    s.pop();
                    j++;
                }
            cur = cur->right = new TreeNode(preorder[i]);  //preorder[i]即当前节点的右子树节点,并且下次从右子树开始遍历
            }
        }
        return root;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值