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

140 阅读1分钟

题目

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

题解

解决这道题,首先我们要先知道二叉树的前序遍历,中序遍历,以及找出二者之间的关系,帮助我们构建出二叉树

前序遍历

先遍历根节点,再递归遍历左子树,最后递归遍历右子树

中序遍历

先递归遍历左子树,再遍历根节点,最后递归遍历右子树

中序遍历和前序遍历的关系

微信截图_20230802094710.png

先序遍历:

  1. pLeft指针指向根节点
  2. [pLeft + 1, pIndex - inLeft + pLeft] 指向左子树
  3. [pIndex - inLeft + pLeft + 1, pRight ] 指向右子树

中序遍历:

  1. pIndex指针指向根节点
  2. [inLeft, pIndex - inLeft - 1 ] 指向左子树
  3. [pIndex + 1, inRight ] 指向右子树

代码

/**
 * Definition for a binary tree node.
 * function TreeNode(val, left, right) {
 *     this.val = (val===undefined ? 0 : val)
 *     this.left = (left===undefined ? null : left)
 *     this.right = (right===undefined ? null : right)
 * }
 */
/**
 * @param {number[]} preorder
 * @param {number[]} inorder
 * @return {TreeNode}
 */
var buildTree = function(preorder, inorder) {
    const pLen = preorder.length;
    const inLen = inorder.length;

    // 检测输入是否合法
    if (pLen != inLen) {
        throw new Error('input is invalid!');
    }

    const inorderMap = new Map();
    // 设置inorder的映射,方便重建二叉树时的快速查找
    for (let i = 0; i < inorder.length; i++) {
        inorderMap.set(inorder[i], i);
    }   

    // 执行递归构建树
    return _buildTree(preorder, 0, pLen - 1, inorderMap, 0, inLen - 1);

    /**
     * @param preorder, 先序遍历数组
     * @param preorderLeft, 先序遍历的左边界 
     * @param preorderRight, 先序遍历的右边界
     * @param inorderMap, 中序遍历 值-索引 映射
     * @param inorderLeft, 中序遍历的左边界
     * @param inorderRight, 中序遍历的右边界
     */
    function _buildTree(preorder, preorderLeft, preorderRight, inorderMap, inorderLeft, inorderRight) {
        // 判断是否为空, 
        if (preorderLeft > preorderRight  || inorderLeft > inorderRight) {
            return null;
        }
        // 根节点值是先序遍历的第一个元素
        const rootVal = preorder[preorderLeft];
        const root = new TreeNode(rootVal);
        // 根节点的索引
        const pIndex = inorderMap.get(rootVal);

        // 构建左子树
        root.left = _buildTree(preorder, preorderLeft + 1,  pIndex - inorderLeft + preorderLeft,  inorderMap, inorderLeft, pIndex - 1);
        // 构建右子树
        root.right = _buildTree(preorder,  pIndex - inorderLeft + preorderLeft + 1, preorderRight, inorderMap, pIndex + 1, inorderRight)

        return root;
    }
};

原题链接

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