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

126 阅读2分钟

Offer 驾到,掘友接招!我正在参与2022春招系列活动-刷题打卡任务,点击查看活动详情

一、题目

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

给定两个整数数组 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 保证 为二叉树的中序遍历序列

二、题解

1.解读 要通过这两种遍历二叉树的结果来构造还原整个二叉树,那么对于前序遍历访问节点的顺序依次为根节点->左节点->右节点,其子树也是如此;对于中序遍历访问节点的顺序依次为左节点->跟节点->右节点,其子树也是如此。只要找到其中一个的特点,再参照另一个就很容易的构造还原二叉树。

方法一 可以将前序遍历的结果看成三个部分[第一部分, 第二部分, 第三部分],第一个部分只有一个元素就是根节点,第二个部分有若干个元素对应是左子树的节点,最后的一部分元素就是右子树的节点,那么我们可以确定前序遍历的第一个元素节点就是根节点;然后对于中序遍历的结果也可以看成三个部分[第一部分, 第二部分, 第三部分],第一部分的元素有若干个为左子树的节点,第二部分的元素只有一个就是根节点,后面第三部分的元素就是右子树的节点。那么我们根据前序遍历的第一个元素节点[根节点]可以在中序遍历找到这个[根节点]的位置,找到这个位置我们就可以确定左子树和右子树的元素节点位置,找到的这个左子树我们再到前序遍历对应找到这些元素节点,那么这样又可以确定左子树的根节点;右子树同理。

三、代码

方法一 Java代码

class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        return buildTree(preorder, inorder, 0, preorder.length - 1, 0, inorder.length - 1);
    }
    public TreeNode buildTree(int[] preorder, int[] inorder, int preLeft, int preRight, int inoLeft, int inoRight) {
        if (preLeft > preRight) {
            return null;
        }
        TreeNode treeNode = new TreeNode(preorder[preLeft]);
        for (int i = inoLeft; i <= inoRight; i++) {
            if (inorder[i] == preorder[preLeft]) {
                int arrLen = i - inoLeft;
                treeNode.left = buildTree(preorder, inorder, preLeft + 1, preLeft + arrLen, inoLeft, i - 1);
                treeNode.right = buildTree(preorder, inorder, preLeft + arrLen + 1, preRight, i + 1, inoRight);
                break;
            }
        }
        return treeNode;
    }
}

时间复杂度:O(n^2),需要递归构造树节点,以及查询根节点位置。

空间复杂度:O(n),递归使用的栈空间。

四、总结

对于每次都需要到中序遍历的结果中查询根节点的位置的时间消耗,可以预先使用哈希表记录下对应元素的下标,来达到O(1)的时间查询。