47.从前序与中序遍历序列构造二叉树(学习)
给定两个整数数组 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 保证 为二叉树的中序遍历序列
解析:
一、找到根节点:
先序遍历的第一个元素是 3,所以根节点是 3。
二、分割中序遍历数组:
1.在中序遍历数组 [9, 3, 15, 20, 7] 中找到 3 的索引,为 1。
2.因此,左子树的中序遍历是 [9],右子树的中序遍历是 [15, 20, 7]。
三、确定子数组的长度:
1.左子树中序遍历的长度是 1,所以左子树先序遍历的长度也是 1(从第二个元素开始,即 9)。
2.右子树的中序遍历长度是 3,所以右子树先序遍历是从 20 开始的 3 个元素([20, 15, 7])。
四、递归构建子树:
1.使用 [9] 和 [9] 构建左子树(注意这里左子树先序遍历和中序遍历都只有一个元素,且相同)。
2.使用 [15, 20, 7] 和 [20, 15, 7] 构建右子树(递归过程相同,但规模更小)。
五、返回根节点:
最终返回构建好的根节点 3,其左子节点是 9,右子树是一个包含 20 为根节点的子树。
var buildTree = function (preorder, inorder) {
if (preorder.length === 0 || inorder.length === 0) {
return null;
}
// 先序遍历的第一个元素是根节点
const rootVal = preorder[0];
let root = new TreeNode(rootVal);
// 在中序遍历中找到根节点的位置
let inorderRootIndex = inorder.indexOf(rootVal);
// 切割中序遍历数组,得到左子树和右子树的中序遍历
const inorderLeft = inorder.slice(0, inorderRootIndex);
const inorderRight = inorder.slice(inorderRootIndex + 1);
// 根据中序遍历的切割,切割先序遍历数组
// 注意,左子树的先序遍历长度应该和中序遍历长度一致
const preorderLeft = preorder.slice(1, 1 + inorderLeft.length);
const preorderRight = preorder.slice(1 + inorderLeft.length);
// 递归构建左子树和右子树
root.left = buildTree(preorderLeft, inorderLeft);
root.right = buildTree(preorderRight, inorderRight);
return root;
};