LeetCode(105):从前序与中序遍历序列构造二叉树

1. 题目描述

2. 题目理解

前序遍历数组的首元素一定是当前子树的根节点。根据这一性质,找到当前子树的根节点,然后查找该节点在中序遍历数组中的位置,可以得到当前根节点左子树中元素的个数。将中序遍历按照根节点分为左右两部分,对应左右子树的中序遍历;同时将前序遍历按照根节点以及根节点左子树中元素的个数,也分成左右两部分对应左右子树的前序遍历

按照以上思路,用递归的方式可以构造出整个树。

3. 代码

3.1 C语言代码

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     struct TreeNode *left;
 *     struct TreeNode *right;
 * };
 */
//递归函数:通过递归,构造二叉树
void bulid(struct TreeNode* head, int* preorder, int preorderSize, int* inorder, int inorderSize);
//找到值为val的元素在当前中序遍历数组中的位置
int findIndex(int val, int* inorder, int inorderSize);
//主函数,提供通用外部接口
struct TreeNode* buildTree(int* preorder, int preorderSize, int* inorder, int inorderSize){
    if(preorderSize==0)return NULL;//传入参数为空,返回NULL
    struct TreeNode* head=(struct TreeNode*)malloc(sizeof(struct TreeNode));
    bulid(head,preorder,preorderSize,inorder,inorderSize);
    return head;
}
//递归函数:通过递归,构造二叉树
void bulid(struct TreeNode* head, int* preorder, int preorderSize, int* inorder, int inorderSize){
    if(preorderSize==0)return;
    //初始化根节点
    head->val=preorder[0];
    head->left=NULL;
    head->right=NULL;
    int idx=findIndex(preorder[0],inorder,inorderSize);//找到根节点在中序遍历中的位置
    if(idx!=0){//存在左子树
        //构造左子树的节点,并初始化
        struct TreeNode* leftRoot=(struct TreeNode*)malloc(sizeof(struct TreeNode));
        leftRoot->val=preorder[1];
        leftRoot->right=NULL;
        leftRoot->left=NULL;
        head->left=leftRoot;//构造左子树的连接
        //更新左子树的前序和中序遍历数组以及数组长度
        //前序遍历数组从preorder[1]开始,到preorder[idx-1],总共idx个元素
        //中序遍历数组从inorder开始,大小与前序遍历数组相等
        int* newPreorder=&preorder[1];
        int newPreorderSize=idx;
        int* newInorder=inorder;
        int newInorderSize=newPreorderSize;
        
        //递归调用,构造左子树
        bulid(leftRoot,newPreorder,newPreorderSize,newInorder,newInorderSize);
    }
    if(idx<inorderSize-1){//存在右子树
        //构造右子树的节点,并初始化
        struct TreeNode* rightRoot=(struct TreeNode*)malloc(sizeof(struct TreeNode));
        rightRoot->val=preorder[idx+1];
        rightRoot->left=NULL;
        rightRoot->right=NULL;
        head->right=rightRoot;//构造右子树的连接
        //更新右子树的前序和中序遍历数组,
        ///前序遍历数组从idx+1开始,数组大小=preorderSize-(idx+1),中序遍历数组相同
        int* newPreorder=&preorder[idx+1];
        int newPreorderSize=preorderSize-idx-1;
        int* newInorder=&inorder[idx+1];
        int newInorderSize=newPreorderSize;
        //递归调用,构造右子树
        bulid(rightRoot,newPreorder,newPreorderSize,newInorder,newInorderSize);
    }
    return;
}
//找到值为val的元素在当前中序遍历数组中的位置
int findIndex(int val, int* inorder, int inorderSize){
    int i=0;
    for(;i<inorderSize;i++){
        if(inorder[i]==val)return i;
    }
    return -1;
}

3.2 C++代码

C++的代码主要用了个哈希表,简化了查找的过程。

/**
 * Definition for a binary tree node.
 * struct TreeNode {
 *     int val;
 *     TreeNode *left;
 *     TreeNode *right;
 *     TreeNode(int x) : val(x), left(NULL), right(NULL) {}
 * };
 */
class Solution {
private:
    unordered_map<int, int> index;
public:
    TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
        int n=preorder.size();
        if(n==0)return NULL;//传入参数为空,返回NULL
        for(int i=0;i<n;i++){//构造哈希表,帮助快速定位根节点
            index[inorder[i]]=i;
        }
        TreeNode* head = new TreeNode(preorder[0]);
        bulid(head,preorder,inorder,0,n-1,0,n-1);
        return head;
    }
    //递归函数:通过递归,构造二叉树
void bulid(struct TreeNode* head, vector<int>& preorder, vector<int>& inorder,
    int preorderLeft,int preorderRight,int inorderLeft,int inorderRight){
    if(!(preorderLeft^preorderRight))return;

    int idx=index[preorder[preorderLeft]];//找到根节点在中序遍历中的位置
    //printf("%d",idx);
    if(idx>inorderLeft){//存在左子树
        //构造左子树的节点,并初始化
        TreeNode* leftRoot=new TreeNode(preorder[preorderLeft+1]);
        head->left=leftRoot;//构造左子树的连接
        //更新左子树的前序和中序遍历数组的范围
        //idx - inorderLeft记录了当前树中根节点左侧的元素的个数(也就是左子树中元素的个数,也就是前序遍历数组的大小)
        //因此前序遍历数组的区间为[preorderLeft+1,preorderLeft + idx - inorderLeft]
        //中序遍历数组按照idx分开,取左边的部分即可
        int newPreorderLeft=preorderLeft+1;
        int newPreorderRight= preorderLeft + idx - inorderLeft;//这个实际是preorderLeft+1+idx-inorderLeft-1
        int newInorderLeft=inorderLeft;
        int newInorderRight=idx-1;
        
        //递归调用,构造左子树
        bulid(leftRoot,preorder,inorder,newPreorderLeft,newPreorderRight,newInorderLeft,newInorderRight);
    }
    if(idx<inorderRight){//存在右子树
        //构造右子树的节点,并初始化
        struct TreeNode* rightRoot=new TreeNode(preorder[preorderLeft+idx-inorderLeft+1]);
        head->right=rightRoot;//构造右子树的连接
        //更新右子树的前序和中序遍历数组的范围
        //前序遍历中,右子树的前序遍历数组紧跟在左子树的前序遍历数组后面,因此newPreorderLeft实际等于newPreorderRight+1
        //中序遍历数组按照idx分开,右边部分属于右子树的中序遍历
        int newPreorderLeft=preorderLeft+idx-inorderLeft+1;
        int newPreorderRight=preorderRight;
        int newInorderLeft=idx+1;
        int newInorderRight=inorderRight;

        //递归调用,构造右子树
        bulid(rightRoot,preorder,inorder,newPreorderLeft,newPreorderRight,newInorderLeft,newInorderRight);
    }
    return;
    }
};

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值