[路飞]_每天刷leetcode_67(从前序与中序遍历序列构造二叉树)

119 阅读1分钟

「这是我参与2022首次更文挑战的第28天,活动详情查看:2022首次更文挑战

从前序与中序遍历序列构造二叉树 Construct binary tree from preorder and inorder traversal

LeetCode传送门105. 从前序与中序遍历序列构造二叉树

题目

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

Given two integer arrays preorder and inorder where preorder is the preorder traversal of a binary tree and inorder is the inorder traversal of the same tree, construct and return the binary tree.

Pasted image 20220214155625.png

输入: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
输出: [3,9,20,null,null,15,7]

输入: preorder = [-1], inorder = [-1]
输出: [-1]

Constraints:

  • 1 <= preorder.length <= 3000
  • inorder.length == preorder.length
  • -3000 <= preorder[i], inorder[i] <= 3000
  • preorder and inorder consist of unique values.
  • Each value of inorder also appears in preorder.
  • preorder is guaranteed to be the preorder traversal of the tree.
  • inorder is guaranteed to be the inorder traversal of the tree.

思考线


解题思路

这道题是根据先序与中序遍历构造二叉树。我们先来看一下什么是先序遍历和中序遍历。

先序遍历:(Pre-order),按照根左右的顺序沿一定路径经过路径上所有的结点。在二叉树中,先根后左再右。巧记:根左右。

中序遍历:(In-order)在二叉树中,中序遍历首先遍历左子树,然后访问根结点,最后遍历右子树。

我们拿到先序遍历的数组,大致可以这样划分[root, 先序遍历左子树, 先序遍历右子树]

我们拿到中序遍历的数组,大致可以这样划分[中序遍历左子树, root, 中序遍历右子树]

我们知道,由于无论是前序遍历还是中序遍历,左右子树的个数肯定是相等的。

再根据先序遍历的第一个元素是根节点,所以我们可以根据这个root,找到中序遍历的root的位置index,在中序遍历中,我们既然找到了rootindex那么,我们也就知道了左右子树的长度,进而我们也就知道了先序遍历的左右子树的长度。

我们用递归来继续处理左右子树,这样我们就可以得到我们想要的二叉树。

值得注意的是,如果前序和中序的数组都是空的时候,证明遍历到了叶子结点,我们直接返回null就可以了。

根据以上思路,我给出自己写出的代码,仅供参考

/**
 * Definition for a binary tree node.
 * class TreeNode {
 *     val: number
 *     left: TreeNode | null
 *     right: TreeNode | null
 *     constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) {
 *         this.val = (val===undefined ? 0 : val)
 *         this.left = (left===undefined ? null : left)
 *         this.right = (right===undefined ? null : right)
 *     }
 * }
 */

function buildTree(preorder: number[], inorder: number[]): TreeNode | null {
    if(!inorder.length || !preorder.length) return null
    const root = preorder.shift();
    const index = inorder.findIndex((v) => v === root);
    const preLeft = preorder.slice(0, index)
    const preRight = preorder.slice(index)
    const left = buildTree(preLeft, inorder.slice(0,index));
    const right = buildTree(preRight, inorder.slice(index+1));
    return new TreeNode(root, left, right)
};

时间复杂度

O(N2)O(N^2):这里 N 是二叉树的结点个数,每调用一次递归方法创建一个结点,一共创建 N个结点,在中序遍历中找到根结点在中序遍历中的位置,是与 N 相关的,这里不计算递归方法占用的时间。

这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。