算法挑战24: 从前序中序遍历构造二叉树

0 阅读2分钟

题目:

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

思路:

给了我们两个数组,一个是前序遍历的结果, 一个是中序遍历的结果

画个图更加直观的表达

image.png (图片来自labuladong)

根据两种遍历结果的特点可知, preorder前序遍历数组的第一个元素是根节点,而在中序遍历数组中根节点在数组中间,两边是左右子树的数组

我们可以利用两个数组的特性来构建整棵二叉树

先从preorder中取第一个元素,也就是当前根节点的值,索引是preStart,值是preorder[preStart]

题目说值不重复,我们可以先把inorder的值和索引存在哈希表中,方便根据根节点的值获取在中序遍历数组中根节点的索引

我们根据root的值获取到根节点在中序遍历数组的值后, 就可以计算出当前根节点的左右子树的数组的长度了

知道子树的长度了,我们就可以在前序遍历数组中切割出左右子树

然后递归构造root节点的左右子树

将分割的子树前序数组的第一个元素构建子树的根节点 ......重复

代码:

var buildTree = function (preorder, inorder) {
    //创建map
    let valToIndex = new Map();
    //提前遍历中序数组
    for (let i = 0; i < inorder.length ; i++) {
        valToIndex.set(inorder[i], i);
    }
    
    return build(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1);
    //构建build函数,参数分别为,前序遍历数组,数组开始索引,结束索引,中序遍历数组,开始索引,结束索引
    function build(preorder, preStart, preEnd, inorder, inStart, inEnd) {
        //出口base case
        if (preStart > preEnd) return null;

        // if (inStart > inEnd) return null;

        //找根节点,就是前序遍历数组的第一个元素
        let rootVal = preorder[preStart];

        //获取根节点在中序遍历数组中的元素索引index
        let index = valToIndex.get(rootVal);

        //计算左右子数组长度,通过中序遍历数组
        let leftLen = index - inStart;
        // let rightLen = inEnd - index;
        
        //构造根节点
        let root = new TreeNode(rootVal);
        //递归构建左右子树
        root.left = build(preorder, preStart + 1, preStart + leftLen, inorder, inStart, index - 1);
        root.right = build(preorder, preStart + leftLen + 1, preEnd, inorder, index + 1, inEnd);
        //返回当前节点
        return root;

    }

};