[路飞]_leetcode-105-从前序与中序遍历序列构造二叉树

444 阅读1分钟

题目描述

[题目地址]

给定一棵树的前序遍历 preorder 与中序遍历  inorder。请构造二叉树并返回其根节点。

示例 1:

Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]

示例 2:

Input: preorder = [-1], inorder = [-1]
Output: [-1]

提示:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder 和 inorder 均无重复元素
  • inorder 均出现在 preorder
  • preorder 保证为二叉树的前序遍历序列
  • inorder 保证为二叉树的中序遍历序列

思路如下:

  1. 前序遍历的顺序为根左右,中序遍历的顺序为左根右,所以 preorder[0] 为当前子树根节点的值
  2. 查找该值在 inorder 中的位置,其左边即为左子树中序遍历序列,右边为右子树中序遍历序列
  3. 获取到左右子树中序遍历后,因为子树前序遍历和中序遍历的结果只是顺序不同,但是序列长度是相同的,所以可以根据左子树中序遍历序列长度去 preorder 获取左子树前序遍历序列,剩余部分即为右子树前序遍历序列
  4. 然后就可以通过根节点的值创建根节点,根据左右子树的前序、中序遍历序列递归创建左右子树
  5. 最后返回二叉树的根节点即可 如图:

image.png image.png

代码实现

 * @param {number[]} preorder
 * @param {number[]} inorder
 * @return {TreeNode}
 */
//  给了我们一个前序遍历数组和中序遍历数组,已知,前序遍历:根左右,中序遍历:左根右
    // 根据遍历的特殊克制,前序遍历数组的第一个元素,是整个树的根节点,我们就获取到根节点的值
    // 在终须遍历数组中,找到根节点的位置mid,我们就可以分割左右子树--左子树0~mid-1,右子树--mid+1~inorder.length-1
var buildTree = function(preorder, inorder) {
    let map = new Map();
    for(let i = 0; i < inorder.length; i++){
        map.set(inorder[i],i)
    }
    const helper = function(pStart, pEnd, iStart, iEnd){
        // 判断我们的前序遍历数组已经使用完毕
        if(pStart > pEnd) return null;
        // 获取根节点的值
        let rootVal = preorder[pStart];
        // 构造一个根节点
        let root = new TreeNode(rootVal);
        // 获取根节点在终须遍历数组中的索引位置,来分隔左右子树
        let mid = map.get(rootVal);
        // 计算左子树的节点个数,用来在前序遍历数组确定左子树结束的位置
        let leftNum = mid - iStart;
        // 递归的构建左子树
        root.left = helper(pStart + 1, pStart + leftNum, iStart,mid -1);
         // 递归的构建右子树
        root.right = helper(pStart + leftNum + 1, pEnd, mid + 1 , iEnd);
        return root;
    }
    return helper(0 , preorder.length -1, 0, inorder.length -1)
};

image.png