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

题目描述:

给定两个整数数组 preorder 和 inorder ,其中 preorder 是二叉树的先序遍历, inorder 是同一棵树的中序遍历,请构造二叉树并返回其根节点。

示例 1:


输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]
示例 2:

输入: preorder = [-1], inorder = [-1]
输出: [-1]
 

提示:

1 <= preorder.length <= 3000
inorder.length == preorder.length
-3000 <= preorder[i], inorder[i] <= 3000
preorder 和 inorder 均 无重复 元素
inorder 均出现在 preorder
preorder 保证 为二叉树的前序遍历序列
inorder 保证 为二叉树的中序遍历序列

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

分析:

这道题思路其实很简单,主要就是实现起来有些麻烦,以及一些边界值。需要计算很多坐标和位置。。。。

        思路就是,前序遍历序列的第一个节点,肯定是根节点,在中序遍历序列中,找到该根节点,位置记为rootindexinorder。

        显然,中序遍历序列中,start~rootindexinorder-1,都是左子树中的节点,统计左子树节点数目nodeleft;rootindexinorder+1~end,都是右子树中的节点,统计右子树节点数目noderight。

        然后在前序遍历序列中,从第二个位置开始(第一个位置为根节点),往后找nodeleft个节点,这是前序遍历序列中,左子树节点的集合。然后再往后找noderight个节点,这是右子树节点的集合。

        构建根节点root。调用递归函数,将前序遍历序列和中序遍历序列中的左子树部分传入递归函数,构造根节点的左子树root->left。调用递归函数,将前序遍历序列和中序遍历序列中的右子树部分传入递归函数,构造根节点的右子树root->right。

思路很简单但是实现起来真的很麻烦啊啊啊啊

代码如下:

/**
 * 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* buildTree(vector<int>& preorder, vector<int>& inorder) {
        return f(preorder,inorder,0,preorder.size()-1,0,inorder.size()-1);
    }
    // 确认函数f的作用:以前序遍历序列的第一个节点为根节点,建立该根节点。计算出该根节点的左子树中节点的数目以及该根节点的右子树中节点的数目。然后在前序遍历序列和中序遍历序列中,给出左子树和右子树的范围。最后通过递归,构建该根节点的左子树和右子树
    // prestart和preend,代表了本次递归中,前序遍历的起始位置和结束位置
    // instart和inend,代表了本次递归中,中序遍历的起始位置和结束位置
    TreeNode* f(vector<int>& preorder, vector<int>& inorder,int prestart,int preend,int instart,int inend)
    {
        // 前序遍历序列不存在或者中序遍历序列不存在,直接返回NULL
        if(prestart>preend||instart>inend) return NULL;
        // 以前序遍历序列中的第一个节点为根节点,构造该根节点
        TreeNode *root=new TreeNode(preorder[prestart]);
        // 得到该根节点在中序遍历序列中的位置
        int rootindexinorder;
        for(int i=instart;i<=inend;i++)
        {
            if(inorder[i]==preorder[prestart])
            rootindexinorder=i;
        }
        // 计算前序遍历中,左子树的起始位置、结束位置;以及右子树的起始和结束位置
        int preleftstart=prestart+1;
        int preleftend=preleftstart+rootindexinorder-instart-1;
        int prerightstart=preleftend+1;
        int prerightend=preend;

        // 计算中序遍历中,左子树的起始位置、结束位置;以及右子树的起始和结束位置
        int inleftstart=instart;
        int inleftend=rootindexinorder-1;
        int inrightstart=rootindexinorder+1;
        int inrightend=inend;
        // 构建根节点的左子树和右子树
        root->left=f(preorder,inorder,preleftstart,preleftend,inleftstart,inleftend);
        root->right=f(preorder,inorder,prerightstart,prerightend,inrightstart,inrightend);
        // 返回该根节点
        return root;

    }
};

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值