889. 根据前序和后序遍历构造二叉树

给定两个整数数组,preorder 和 postorder ,其中 preorder 是一个具有 无重复 值的二叉树的前序遍历,postorder 是同一棵树的后序遍历,重构并返回二叉树。

如果存在多个答案,您可以返回其中 任何 一个。

示例 1:

输入:preorder = [1,2,4,5,3,6,7], postorder = [4,5,2,6,7,3,1]
输出:[1,2,3,4,5,6,7]

示例 2:

输入: preorder = [1], postorder = [1]
输出: [1]

提示:

    1 <= preorder.length <= 30
    1 <= preorder[i] <= preorder.length
    preorder 中所有值都 不同
    postorder.length == preorder.length
    1 <= postorder[i] <= postorder.length
    postorder 中所有值都 不同
    保证 preorder 和 postorder 是同一棵二叉树的前序遍历和后序遍历

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

方法一:递归

思路

前序遍历为:

    (根结点) (前序遍历左分支) (前序遍历右分支)

而后序遍历为:

    (后序遍历左分支) (后序遍历右分支) (根结点)

例如,如果最终的二叉树可以被序列化的表述为 [1, 2, 3, 4, 5, 6, 7],那么其前序遍历为 [1] + [2, 4, 5] + [3, 6, 7],而后序遍历为 [4, 5, 2] + [6, 7, 3] + [1].

如果我们知道左分支有多少个结点,我们就可以对这些数组进行分组,并用递归生成树的每个分支。

算法

我们令左分支有 LLL 个节点。我们知道左分支的头节点为 pre[1],但它也出现在左分支的后序表示的最后。所以 pre[1] = post[L-1](因为结点的值具有唯一性),因此 L = post.indexOf(pre[1]) + 1。

现在在我们的递归步骤中,左分支由 pre[1 : L+1] 和 post[0 : L] 重新分支,而右分支将由 pre[L+1 : N] 和 post[L : N-1] 重新分支。

作者:LeetCode
链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/solution/gen-ju-qian-xu-he-hou-xu-bian-li-gou-zao-er-cha-sh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

class Solution {
    public TreeNode constructFromPrePost(int[] pre, int[] post) {
        int N = pre.length;
        if (N == 0) return null;
        TreeNode root = new TreeNode(pre[0]);
        if (N == 1) return root;

        int L = 0;
        for (int i = 0; i < N; ++i)
            if (post[i] == pre[1])
                L = i+1;

        root.left = constructFromPrePost(Arrays.copyOfRange(pre, 1, L+1),
                                         Arrays.copyOfRange(post, 0, L));
        root.right = constructFromPrePost(Arrays.copyOfRange(pre, L+1, N),
                                          Arrays.copyOfRange(post, L, N-1));
        return root;
    }
}


作者:LeetCode
链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/solution/gen-ju-qian-xu-he-hou-xu-bian-li-gou-zao-er-cha-sh/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

解题思路

【生哥刷题】【单片机工程师】
----这里道题目用C语言来做的思路。
树的定义

树是n个结点的有限集。当n=0时,称为空树。
二叉树的定义

二叉树是n个结点的有限集。当n=0时,称为空树,当n不等于0时,根结点包含一个或两个的子树,分别称为左子树个右子树。
二叉树的特点

1.每个结点最多只有两个子树。
2:左子树和右子树是顺序的。
二叉树的抽象表示方法

ADT
{
    leftNode;   //左子结点
    rightNode;  //右子结点
    data;       //数据结点
}

二叉树的遍历方法:

二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中的所有结点,使得每个结点都被访问。
关键词:次序 访问
访问:根据具体内容,完成指定的操作
次序:严格按照的顺序完成操作
1:前序遍历->根左右
规则如是二叉树为空,则返回空操作,否则先访问根结点,然后前序遍历左子树,最后前序遍历右子树。

抽象表示:
void pre(Tree)          //preOrder
{
    Tree = Null return;
    Tree.data           //操作
    pre(Tree.leftNode);
    pre(Tree.rightNode);
}

前序遍历题目

2:中序遍历->左根右
规则如是二叉树为空,则返回空操作,然后中序遍历左子树,访问根结点,最后中序遍历右子树。

抽象表示:
void InO(Tree)          //InOrder
{
    Tree = Null return;
    InO(Tree.leftNode);
    Tree.data           //操作
    InO(Tree.rightNode);
}

中序遍历题目

3:后续遍历->左右根
规则如是二叉树为空,则返回空操作,然后后序遍历左子树,后序遍历右子树,最后访问根结点,

抽象表示:
void Pos(Tree)          //PostOrder
{
    Tree = Null return;
    Pos(Tree.leftNode);
    Pos(Tree.rightNode);
    Tree.data           //操作
}

后序遍历题目

4:层序遍历
借助其他数据结构,记录下,Tree的下一层的所有结点。这样一层一层的遍历。直到结束

抽象表示:
void Lev(Queue Tree)        //levelOrder
{
    while(Tree != NULL)
    {
        Tree.data               //操作
        Queue push Tree.leftNode;
        Queue push Tree.rightNode;
        Queue pop  Tree;
    }
}

层序遍历题目
构造二叉树的方法

根据树的遍历方法有3种,前序遍历,中序遍历,后序遍历
带来的构造二叉树的方法
分为[前序,中序],[前序,后序],[中序,后序]
1:[前序,中序]构造二叉树。
通过前序,确定每个根节点。前序第一个值为根结点。
通过根节点的值,查找中序,可以确定根结点。左子树结点和右子树结点数量
通过数组获取新的前序数组,后序数组,遍历左子树,右子树,完成构造。

抽象表示:
void bulidTree(root, Preorder,InOrder)
{
    root = Preorder[0];
    Preorder[0] find in InOrder = count;
    leftNum = count;
    newPreorder = Preorder[1,1+leftNum];
    newInOrder  = InOrder [0,leftNum];
    bulidTree(root.leftNode, newPreorder,newInOrder);
    free(newPreorder);
    free(newInOrder);
    
    rightNum = preorderSize - count - 1;
    newPreorder = Preorder[count + 1,rightNum];
    newInOrder  = InOrder [count + 1,rightNum];
    bulidTree(root.rightNode,newPreorder,newInOrder);
    free(newPreorder);
    free(newInOrder);
}

时间复杂度O(n)
空间复杂度O(n)
题目前中序构造二叉树
图片.png

2: [前序,后序]构造二叉树。 答案可能不唯一
通过前序,确定每个根节点。前序第一个值为根结点。
通过在后序中查找第二个值,来判断左右子树的长度

抽象表示:
void bulidTree(root, Preorder,PostOrder)
{
    root = Preorder[0];
    Preorder[1] find in PostOrder = count;
    leftNum = count;
    newPreorder = Preorder[1,1+leftNum];
    newPostOrder= InOrder [0,leftNum];
    bulidTree(root.leftNode, newPreorder,newPostOrder);
    free(newPreorder);
    free(newPostOrder);
    
    rightNum      = preorderSize - count - 1;
    newPreorder   = Preorder[count + 1,rightNum];
    newPostOrder  = InOrder [count,    rightNum];
    bulidTree(root.rightNode,newPreorder,newPostOrder);
    free(newPreorder);
    free(newPostOrder);
}

时间复杂度O(n)
空间复杂度O(n)
题目前后序构造二叉树

图片.png

3: [中序,后序]构造二叉树。
通过后序,确定每个根节点。后序最后一个值为根结点。
通过根节点的值,查找中序,可以确定根结点。左子树结点和右子树结点数量
通过数组获取新的中序数组,后序数组,遍历左子树,右子树,完成构造。

抽象表示:
void bulidTree(root, InOrder,PostOrder)
{
    root = PostOrder[last];
    PostOrder[0] find in InOrder = count;
    leftNum = count;
    newPostOrder = PostOrder[0,leftNum];
    newInOrder   = InOrder [0,leftNum];
    bulidTree(root.leftNode, newInOrder,newPostOrder);
    free(newPostOrder);
    free(newInOrder);
    
    rightNum = PostOrderSize - count - 1;
    newPostOrder = PostOrder[count + 1,rightNum];
    newInOrder   = InOrder [count + 1,rightNum];
    bulidTree(root.rightNode,newInOrder,newPostOrder);
    free(newPostOrder);
    free(newInOrder);
}

时间复杂度O(n)
空间复杂度O(n)

作者:goodgoodday
链接:https://leetcode.cn/problems/construct-binary-tree-from-preorder-and-postorder-traversal/solution/gen-ju-qian-xu-he-hou-xu-bian-li-gou-zao-wq2v/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值