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

3 阅读1分钟

题目链接

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

解法1 暴力解法

思路

前序遍历的第一个节点是根节点,而根据根节点的值,再到中序遍历中寻找根节点,而这根节点左边则是左子树,右边则是右子树。递归处理即可。

代码

function buildTree(preorder: number[], inorder: number[]): TreeNode | null {
    if (preorder.length === 0 || inorder.length === 0) {
        return null;
    }

    // 第一个是根节点
    const rootVal = preorder[0];
    const root = new TreeNode(rootVal);

    // 在中序遍历中找这个值的位置
    const midIndex = inorder.indexOf(rootVal);

    // 递归构建左子树和右子树
    root.left = buildTree(preorder.slice(1, 1 + midIndex), inorder.slice(0, midIndex));
    root.right = buildTree(preorder.slice(1 + midIndex), inorder.slice(midIndex + 1));

    return root;
};

时空复杂度

主要是 slice 复制数组的时空开销

时间复杂度:O(n^2)

空间复杂度:O(n^2)

解法2 map优化索引

思路

这个方法就是对于上面暴力解法的优化,通过哈希表来存储中序遍历的索引。具体执行逻辑其实没有区别。

代码

function buildTree(preorder: number[], inorder: number[]): TreeNode | null {
    const indexMap = new Map();
    for (let i = 0; i < inorder.length; i++) {
        indexMap.set(inorder[i], i);
    }

    let preIndex = 0;

    const helper = (left, right) => {
        if (left > right) return null;

        const rootVal = preorder[preIndex++];
        const root = new TreeNode(rootVal);
        const index = indexMap.get(rootVal);

        root.left = helper(left, index - 1);
        root.right = helper(index + 1, right);

        return root;
    }

    return helper(0, inorder.length - 1);
};

时空复杂度

时间复杂度:O(n)

空间复杂度:O(n)