根据数组构造二叉树最强解法总结

方法论

构造二叉树题目一般都是用数组构造,可以两个数组或者一个数组构造。
用两个数组构造一棵二叉树的递归函数需要四个参数,每个数组都要指定起始和结束位置:

TreeNode* build(vector<int>& inorder, int inbegin, int inend, vector<int>& postorder, int postbegin, int postend){}

题目包括:
    LT106 从中序与后序遍历序列构造二叉树
    LT105 从前序与中序遍历序列构造二叉树
用一个数组构造一棵二叉树只需要2个参数,指定起始和结束位置:

TreeNode* build(vector<int>& nums, int begin, int end){}

题目包括:
    LT654  最大二叉树
    LT108 有序数组转换为二叉搜索树

不管是几个数组,最终的代码写法都是很相似的。分为几个步骤:
1.找到分割点,也就是根节点
2.切割数组,如果是两个数组的,需要分别切割
3.递归构造左右子树,递归函数的返回值给root节点
另外代码编写过程中要坚持循环不变量原则,统一使用左闭右开原则。

LT106 从中序与后序遍历序列构造二叉树


循环不变量:左闭右开
方法一:使用临时数组,这种方法空间复杂度比较大,时间复杂度也大,容易超时
注意类似用数组构造二叉树的题目,每次分隔尽量不要定义新的数组,而是通过下表索引直接在原数组上操作,这样可以节约时间和空间上的开销。

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode() : val(0), left(nullptr), right(nullptr) {}
*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
    TreeNode* build(vector<int>& inorder, vector<int>& postorder){
        cout << endl << "inorder:";
        for(auto &it:inorder)
            cout << "," << it;
        cout << endl << "postorder:";
        for(auto &it:postorder)
            cout << "," << it;
        if(inorder.size() == 0 || postorder.size() == 0) return NULL;
        TreeNode* root = new TreeNode(postorder[postorder.size() - 1]);
        if(postorder.size() == 1){
            return root;
        }
        //找到中序数组的切割点
        int i = 0;
        for(; i < inorder.size(); i++){
            if(inorder[i] == postorder[postorder.size() - 1])
                break;
        }
        //拆分中序数组:中左和中右
        vector<int> inleft(inorder.begin(), inorder.begin() + i);
        vector<int> inright(inorder.begin() + i + 1, inorder.end());
        //拆分后序数组:后左和后右
        postorder.resize(postorder.size() - 1);
        vector<int> postleft(postorder.begin(), postorder.begin() + inleft.size());
        vector<int> postright(postorder.begin() + inleft.size(), postorder.end());
        //递归处理中左和后左、中右和后右
        root->left = build(inleft, postleft);
        root->right = build(inright, postright);


        cout << "end..."<<endl;  //只会执行一次,返回的就是整棵树的root节点
        return root;
    }


    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        return build(inorder, postorder);
    }
};

使用下标索引:

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode() : val(0), left(nullptr), right(nullptr) {}
*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
    unordered_map<int, int> inordermap; //存储中序数组中值和下标的映射关系
    TreeNode* build(vector<int>& inorder, int inbegin, int inend, vector<int>& postorder, int postbegin, int postend){
        cout << "inbegin:" << inbegin << ",inend:" << inend << ",postbegin:" << postbegin << ",postend:" << postend << endl;
        if(postbegin == postend) return NULL;
        TreeNode* root = new TreeNode(postorder[postend - 1]);
        if(postend - postbegin == 1) return root;
        //1.找到中序数组的切割点
        int i = inordermap[postorder[postend - 1]];
        
        //2.拆分中序数组,左闭右开,中左[inleftbegin, inleftend)和中右[inrightbegin, inrightend)
        int inleftbegin = inbegin;
        int inleftend = i;
        int inrightbegin = i + 1;
        int inrightend = inend;
        //3.拆分后序数组,左闭右开,后左[postleftbegin, postleftend)和后右[postrightbegin, postrightend)
        int postleftbegin = postbegin;
        int postleftend = postleftbegin + (i - inbegin);
        int postrightbegin = postleftend;  //注意这里不是postleftend+1
        int postrightend = postend - 1;
        //4.递归处理中左和后左、中右和后右
        root->left = build(inorder, inleftbegin, inleftend, postorder, postleftbegin, postleftend);
        root->right = build(inorder, inrightbegin, inrightend, postorder, postrightbegin, postrightend);


        return root;
    }

    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        int idx = 0;
        for(auto &it : inorder)
            inordermap[it] = idx++;


        return build(inorder, 0, inorder.size(), postorder, 0, postorder.size());
    }
};


LT105 从前序与中序遍历序列构造二叉树

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode() : val(0), left(nullptr), right(nullptr) {}
*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
    unordered_map<int, int> inordermap;

    TreeNode* build(vector<int>& inorder, int inbegin, int inend, vector<int>& preorder, int prebegin, int preend){
        cout << "inbegin:"<<inbegin<<",inend:"<<inend<<",prebegin:"<<prebegin<<",preend:"<<preend<<endl;
        if(prebegin == preend) return NULL;
        TreeNode* root = new TreeNode(preorder[prebegin]);
        if(preend - prebegin == 1) return root;
        
        //找到中序数组的切割点
        int i = inordermap[preorder[prebegin]];
        //拆分中序数组,中左和中右
        int inleftbegin = inbegin;
        int inleftend = i;
        int inrightbegin = i + 1;
        int inrightend = inend;
        //拆分前序数组,前左和前右
        int preleftbegin = prebegin + 1;
        int preleftend = preleftbegin + (i - inbegin);
        int prerightbegin = preleftend;
        int prerightend = preend;
        //递归处理中左和前左、中右和前右
        root->left = build(inorder, inleftbegin, inleftend, preorder, preleftbegin, preleftend);
        root->right = build(inorder, inrightbegin, inrightend, preorder, prerightbegin, prerightend);

        return root;
    }

    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        
        int idx = 0;
        for(auto &it : inorder){
            inordermap[it] = idx++;
        }
            
        return build(inorder, 0, inorder.size(), preorder, 0, preorder.size());
    }
};

LT654  最大二叉树


给定一个不含重复元素的整数数组 nums 。一个以此数组直接递归构建的 最大二叉树 定义如下:

二叉树的根是数组 nums 中的最大元素。
左子树是通过数组中 最大值左边部分 递归构造出的最大二叉树。
右子树是通过数组中 最大值右边部分 递归构造出的最大二叉树。
返回有给定数组 nums 构建的 最大二叉树 。

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode() : val(0), left(nullptr), right(nullptr) {}
*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
    TreeNode* build(vector<int>& nums, int begin, int end){
        if(begin == end) return NULL;
        
        //找到[begin, end)范围最大值的下标maxvalueidx
        int maxvalue = nums[begin];
        int maxvalueidx = begin;
        int i = begin;
        for(; i < end; i++){
            if(nums[i] > maxvalue){
                maxvalue = nums[i];
                maxvalueidx = i;
            }
        }
        TreeNode* root = new TreeNode(nums[maxvalueidx]);
        if(end - begin == 1) return root;

        //左子树
        int leftbegin = begin;
        int leftend = maxvalueidx;
        //右子树
        int rightbegin = maxvalueidx + 1;
        int rightend = end;
        //分别递归处理左子树、右子树
        root->left = build(nums, leftbegin, leftend);
        root->right = build(nums, rightbegin, rightend);

        return root;
    }

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

LT108 有序数组转换为二叉搜索树


给你一个整数数组 nums ,其中元素已经按 升序 排列,请你将其转换为一棵 高度平衡 二叉搜索树。
高度平衡 二叉树是一棵满足「每个节点的左右两个子树的高度差的绝对值不超过 1 」的二叉树。
思路:因为数组本身就是有序的,每次选择中间的节点作为根节点,构造出来的肯定就是二叉搜索树,那是不是就平衡呢?仔细想一想,构成平衡树是自然而然的事情,因为每次选择中间元素,左右的个数都是相同的,最多差一个。

/**
* Definition for a binary tree node.
* struct TreeNode {
*     int val;
*     TreeNode *left;
*     TreeNode *right;
*     TreeNode() : val(0), left(nullptr), right(nullptr) {}
*     TreeNode(int x) : val(x), left(nullptr), right(nullptr) {}
*     TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {}
* };
*/
class Solution {
public:
    TreeNode* build(vector<int>& nums, int begin, int end){
        if(begin == end) return NULL;
        //找到分割点
        int i = (end - begin)/2 + begin;
        TreeNode* root = new TreeNode(nums[i]);
        //左子树
        int leftbegin = begin;
        int leftend = i;
        //右子树
        int rightbegin = i + 1;
        int rightend = end;
        //递归构造子子树和右子树
        root->left = build(nums, leftbegin, leftend);
        root->right = build(nums, rightbegin, rightend);

        return root;
    }

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

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值