二叉树的构造:从中序和后序序列构造二叉树(前序遍历)

中 + 后构造二叉树
在这里插入图片描述
一层层切割,故想到递归

  1. 如果数组大小为0,说明是空结点
  2. 如果不为空,则去后序数组最后一个元素作为节点元素
  3. 找到后序数组最后一个元素在中序数组的位置,作为切割点
  4. 切割中序数组,切割为中序左数组中序右数组(一定是先切割中序数组)
  5. 切割后序数组,切为后序左数组后序右数组
  6. 递归处理左区间右区间

中序数组大小一定是和后序数组的大小相同的(这是必然)。
故可以根据切好的中序来分割后序

class Solution {
public:
//inorder.size() == postorder.size()
    TreeNode* traverse(vector<int>& inorder, vector<int>& postorder){
        //有可能上一层postorder.size() = 2, 从而一边有孩子,一边没有孩子
        if(postorder.size() == 0) return NULL;//空结点?

        int rootValue = postorder[postorder.size() - 1];
        TreeNode* root = new TreeNode(rootValue);

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

        int delimiterIndex;
        for(delimiterIndex = 0; delimiterIndex < inorder.size(); delimiterIndex++){
            if(inorder[delimiterIndex] == rootValue)
                break;
        } 
        //切割中序数组
        //左闭右开,长度为右index-左index 
        //[0, delimiterIndex)
        vector<int> leftInorder(inorder.begin(), inorder.begin() + delimiterIndex);
        vector<int> rightInoder(inorder.begin() + delimiterIndex + 1, inorder.end());

        //remove the last element
        postorder.resize(postorder.size() - 1);

        //切割后序数组
        vector<int> leftPost(postorder.begin(), postorder.begin() + leftInorder.size());
        vector<int> rightPost(postorder.begin() + leftInorder.size(), postorder.end());

        root->left = traverse(leftInorder, leftPost);
        root->right = traverse(rightInoder, rightPost);

        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        if(inorder.size() == 0 || postorder.size() == 0)
        return NULL;

        return traverse(inorder, postorder);
    }
};

如上的代码性能并不好,应为每层递归定定义了新的vector(就是数组),既耗时又耗空间,但上面的代码是最好理解的,为了方便读者理解,所以用如上的代码来讲解。

下面给出用下表索引写出的代码版本:(思路是一样的,只不过不用重复定义vector了,每次用下表索引来分割)

class Solution {
private:
    // 中序区间:[inorderBegin, inorderEnd),后序区间[postorderBegin, postorderEnd)
    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 delimiterIndex;
        for (delimiterIndex = inorderBegin; delimiterIndex < inorderEnd; delimiterIndex++) {
            if (inorder[delimiterIndex] == rootValue) break;
        }
        // 切割中序数组
        // 左中序区间,左闭右开[leftInorderBegin, leftInorderEnd)
        int leftInorderBegin = inorderBegin;
        int leftInorderEnd = delimiterIndex;
        // 右中序区间,左闭右开[rightInorderBegin, rightInorderEnd)
        int rightInorderBegin = delimiterIndex + 1;
        int rightInorderEnd = inorderEnd;

        // 切割后序数组
        // 左后序区间,左闭右开[leftPostorderBegin, leftPostorderEnd)
        int leftPostorderBegin =  postorderBegin;
        int leftPostorderEnd = postorderBegin + delimiterIndex - inorderBegin; // 终止位置是 需要加上 中序区间的大小size
        // 右后序区间,左闭右开[rightPostorderBegin, rightPostorderEnd)
        int rightPostorderBegin = postorderBegin + (delimiterIndex - 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());
    }
};

最终简化版

class Solution {
private:
    // 中序区间:[b1, e1),后序区间[b2, e2)
    TreeNode* traversal (vector<int>& inorder, int b1, int e1, vector<int>& postorder, int b2, int e2) {
        if(e2 == b2) return NULL;

        int midValue = postorder[e2 - 1];
        TreeNode* root = new TreeNode(midValue);

        if(e2 - b2 == 1) return root;

        int delimiter;
        for(delimiter = b1; delimiter < e1; delimiter++){
            if(inorder[delimiter] == midValue) break;
        }

        root->left = traversal(inorder, b1, delimiter, postorder, b2, b2 + delimiter - b1);
        root->right = traversal(inorder, delimiter + 1, e1, postorder, b2 + delimiter - b1 , e2-1);

        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());
    }
};

中+前构造二叉树:
和后+中道理一样

class Solution {
public:
    TreeNode* traversal(vector<int>& preorder, int b1, int e1, vector<int>& inorder, int b2, int e2){
        if(e2 == b2) return NULL;

        int midValue = preorder[b1];
        TreeNode* root = new TreeNode(midValue);

        if(e2 - b2 == 1) return root;

        int dilimiter;
        for(dilimiter = b2; dilimiter < e2; dilimiter++){
            if(inorder[dilimiter] == midValue) break;
        }


        root->left = traversal(preorder, b1 + 1, b1 + 1 + (dilimiter - b2), inorder, b2, dilimiter);
        root->right = traversal(preorder, b1 + 1 + (dilimiter - b2), e1, inorder, dilimiter + 1, e2);

        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        if(preorder.size() == 0 || inorder.size() == 0)
            return NULL;
        
        return traversal(preorder, 0, preorder.size(), inorder, 0, inorder.size());
    }
};

在这里插入图片描述
在这里插入图片描述
思路和上面两题思路一样

构造二叉树一般都是前序遍历,因为得先构造中间结点,然后再递归构造左子树和右子树

class Solution {
public:
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        if(nums.size() == 0) return NULL;

        int maxValue = -1;
        int maxIndex;
        for(int i = 0; i < nums.size(); i++){
            if(nums[i] > maxValue){
                maxValue = nums[i];
                maxIndex = i;
            }
        }

        TreeNode* root = new TreeNode(maxValue);

        if(nums.size() == 1) return root;
        //左闭右开
        vector<int> leftNums(nums.begin(), nums.begin() + maxIndex);
        //左闭右开
        vector<int> rightNums(nums.begin() + maxIndex + 1, nums.end());

        root->left = constructMaximumBinaryTree(leftNums);
        root->right = constructMaximumBinaryTree(rightNums);

        return root;

    }
};

因为每次都要构造新的vector,所以效率不高,可以使用下标索引的方法来直接在原数组上构造二叉树
注意易错点:

class Solution {
public:
    TreeNode* constructBinaryTree(vector<int>& nums, int start, int end) {
        if(start == end) return NULL; //**易错

        int maxValue = -1;
        int maxIndex;
        for(int i = start; i < end; i++){ //*易错
            if(nums[i] > maxValue){
                maxValue = nums[i];
                maxIndex = i;
            }
        }

        TreeNode* root = new TreeNode(maxValue);

        if(end - start == 1) return root; //易错
        

        root->left = constructBinaryTree(nums, start, maxIndex); 易错
        root->right = constructBinaryTree(nums, maxIndex + 1, end); //易错

        return root;

    }

    TreeNode* constructMaximumBinaryTree(vector<int>& nums){
        return constructBinaryTree(nums, 0, nums.size());
    }
};

在这里插入图片描述

前序遍历:(自己)

内存耗费很高 因为构造了一颗新树,每次都要构造一个新结点

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(!root1 && !root2) return NULL;

        int midValue;
        TreeNode* root = new TreeNode(0);
        if(root2 && root1){
            midValue = root1->val + root2->val;
            
            root->val = midValue;
            root->left = mergeTrees(root1->left, root2->left);
        root->right = mergeTrees(root1->right, root2->right);
        } 
        else if(root1 && !root2){
            midValue = root1->val;
            
            root->val = midValue;
            root->left = mergeTrees(root1->left, NULL);
            root->right = mergeTrees(root1->right, NULL);
            
        } 
        else if(!root1 && root2){
            midValue = root2->val;
            
            root->val = midValue;
            root->left = mergeTrees(NULL, root2->left);
            root->right = mergeTrees(NULL,root2->right);
            
        }

        

        return root;
    }
};

改进:
以root1为基础构造新树

class Solution {
public:
    TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) {
        if(!root1) return root2;
        if(!root2) return root1;

        root1->val += root2->val;

        root1->left = mergeTrees(root1->left, root2->left);
        root1->right = mergeTrees(root1->right, root2->right);

        return root1;

    }
};

这题前中后都行

在这里插入图片描述

class Solution {
public:
    TreeNode* createSearch(vector<int>& nums, int start, int end){
        //严格按照左闭又开的原则
        if(start == end) return NULL;
        int mid = (start + end) / 2;
        TreeNode* root = new TreeNode(nums[mid]);

        if(start + 1 == end) return root;

        root->left = createSearch(nums, start, mid);
        root->right = createSearch(nums, mid + 1, end);  

        return root;


    }
    TreeNode* sortedArrayToBST(vector<int>& nums) {

        return createSearch(nums, 0,  nums.size());
    }
};
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值