【LeetCode】【C++/C#】105.从前序与中序遍历序列构造二叉树 106.从中序与后序遍历序列构造二叉树 654. 最大二叉树


1. 从前序与中序遍历序列构造二叉树 (中序与后序同理)

方法1:利用根结点位置不断递归分割出数组中的左子树和右子树

public class Solution {
    public TreeNode BuildTree(int[] preorder, int[] inorder) {
        TreeNode root=new TreeNode();
        if(preorder.Length==0)
            return root=null;
        // 二叉树不为空 直到根结点在前序遍历以及后序遍历中的位置,然后找到根结点在中序遍历中的位置
        root.val=preorder[0];

        // 如果数组长度为1,递归传入的数组值就是根结点的值,然后直接返回,代码不需要往下进行(小优化)
        if(preorder.Length==1)
            return root;

        // 找到根结点在中序遍历中的位置 这样就可以分出数组中的左子树结点和右子树结点
        int k=0;
        for(int i=0;i<inorder.Length;i++)
        {
            if(root.val==inorder[i])
            {
                k=i;
                break;
            }
                
        }
        
        // 根的左子树由k个结点组成,特征为:前序序列--preorder[1],...,preorder[k] 中序序列--inorder[0],...inorder[k-1]
        // 根的右子树由初始序列长度(preorder.Length)-1-k个结点组成,特征为:
        // 前序序列--preorder[k+1],...,preorder[preorder.Length-1] 中序序列--inorder[k+1],...,inorder[inorder.Length-1]

        // 定义数组,存储对应遍历序列中对应索引左右子树结点值
        int[] preLeftTree=new int[k];
        int[] inLeftTree=new int[k];// 根据前中遍历序列可知左子树由k个结点组成

        int[] preRightTree=new int[preorder.Length-1-k];
        int[] inRightTree=new int[preorder.Length-1-k];// 右子树同理
        if(preorder.Length>0)
        {
            // 向左子树数组中添加对应元素(从0索引处添加) 这里使用for循环为了给定义的初始数组赋值,随便用几个for循环都可以
            for(int i=0;i<k;i++)
            {
                preLeftTree[i]=preorder[i+1];// 前序序列中对应的左子树结点存储数组中
                inLeftTree[i]=inorder[i];// 中序序列中对应的左子树结点存储数组中
            }
            // 左子树递归
            root.left=BuildTree(preLeftTree,inLeftTree);
            // 向右子树数组中添加对应元素
            int index=0;// 索引为0,从数组初始位置开始存储结点的值
            for(int i=k+1;i<preorder.Length;i++)
            {
                preRightTree[index]=preorder[i];// 同理
                inRightTree[index]=inorder[i];
                index++;
            }
            // 右子树递归
            root.right=BuildTree(preRightTree,inRightTree);
        }
        return root;
    }
}

前序和后序遍历序列不能构造二叉树,因为根结点在两个序列的两端,并不能根据根结点的位置分割数组,也就是不能找出根结点root的左子树和右子树,所以不能唯一确定一颗二叉树。

方法2:利用左右子树在vector中对应的区间构建二叉树,避免方法1每次递归创建数组带来时间与空间上的消耗,同时使用hashmap,避免循环在中序序列中查找根节点下标带来时间上的消耗

/**
 * 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> hash;
    // 确定递归的参数和返回值
    TreeNode* build(vector<int>& preorder,int preorderBegin,int preorderEnd,vector<int>& inorder,int inorderBegin,int inorderEnd)
    {
        // 如果左右子树的遍历序列为空,返回nullptr
        if(preorderBegin>preorderEnd)
            return nullptr;
        // 找到根节点所在位置索引
        int k=hash[preorder[preorderBegin]];
        TreeNode* root=new TreeNode(preorder[preorderBegin]);// 根节点

        int leftSize=k-inorderBegin;
        
        // 左子树节点个数 k-0 右子树节点个数inorder.size()-k-1
        // 前序与中序 左子树所在区间
        root->left=build(preorder,preorderBegin+1,preorderBegin+leftSize,inorder,inorderBegin,k-1);
        // 前序与中序 右子树所在区间
        root->right=build(preorder,preorderBegin+leftSize+1,preorderEnd,inorder,k+1,inorderEnd);


        return root;
        
    }
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        // 避免使用循环在中序遍历序列中找到根节点所在的位置,这里使用unorder_map存储inorder中的所有元素,key为元素值,value为索引
        for(int i=0;i<inorder.size();++i)
        {
            hash[inorder[i]]=i;//key为结点值 value为索引
        }
        // 这里传入不同遍历序列的左子树、右子树所在区间***索引***
        return build(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1);
    }
};

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

/**
 * 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> hash;// 因为遍历序列都由不同的值组成,所以不用使用maltimap
    // 确定递归参数和返回值
    TreeNode* myBuild(vector<int>& inorder,int inorderBegin,int inorderEnd,vector<int>& postorder,int postorderBegin,int postorderEnd)
    {
        // 递归终止条件
        if(inorderBegin>inorderEnd)
            return nullptr;
        int k=hash[postorder[postorderEnd]];// 中序根节点所在索引,该索引可以将其分为左右子树
        TreeNode* root=new TreeNode(postorder[postorderEnd]);// 创建根节点

        // 左子树数量
        int leftSize=k-inorderBegin;

        // 确定递归的单层逻辑
        // 填入中序序列左子树在vector中索引(前闭后闭) 后序也是左子树的索引
        root->left=myBuild(inorder,inorderBegin,k-1,postorder,postorderBegin,postorderBegin+leftSize-1);
        // 同理


        root->right=myBuild(inorder,k+1,inorderEnd,postorder,postorderBegin+leftSize,postorderEnd-1);

        return root;
    }
    TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) {
        // 向哈希表填入数据
        for(int i=0;i<inorder.size();++i)
        {
            hash[inorder[i]]=i;// key为节点值,value为节点下标索引
        }
        return myBuild(inorder,0,inorder.size()-1,postorder,0,postorder.size()-1);
    }
};

3. 最大二叉树

/**
 * 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* myBuild(vector<int>& nums,int begin,int end)
    {
        if(begin>end)
            return nullptr;
        // 找到数组中根节点的索引
        int k=begin;            // 初始化 k为nums中最大值下标
        int maxValue=nums[begin];// 找到最大值
        // 时间复杂度O(n)
        for(int i=begin;i<=end;++i)
        {
            if(nums[i]>maxValue)
            {
                k=i;
                maxValue=nums[i];
            }
        }

        TreeNode* root=new TreeNode(nums[k]);
        root->left=myBuild(nums,begin,k-1);
        root->right=myBuild(nums,k+1,end);
        return root;
    }
    TreeNode* constructMaximumBinaryTree(vector<int>& nums) {
        
        return myBuild(nums,0,nums.size()-1);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值