「这是我参与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.
输入: 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,在中序遍历中,我们既然找到了root的index那么,我们也就知道了左右子树的长度,进而我们也就知道了先序遍历的左右子树的长度。
我们用递归来继续处理左右子树,这样我们就可以得到我们想要的二叉树。
值得注意的是,如果前序和中序的数组都是空的时候,证明遍历到了叶子结点,我们直接返回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)
};
时间复杂度
:这里 N 是二叉树的结点个数,每调用一次递归方法创建一个结点,一共创建 N个结点,在中序遍历中找到根结点在中序遍历中的位置,是与 N 相关的,这里不计算递归方法占用的时间。
这就是我对本题的解法,如果有疑问或者更好的解答方式,欢迎留言互动。