原题连接:https://leetcode-cn.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/
解题思路:
- 参考了多种解法,逐渐优化(补充国外大佬解法)和动画演示 105. 从前序与中序遍历序列构造二叉树。
- 假设有一个二叉树如下:
1
/ \
2 3
/ \ / \
4 5 6 7
前序遍历的结果是: [1,2,4,5,3,6,7]
中序遍历的结果是: [4,2,5,1,6,3,7]
- 可以将其从根节点1,拆分成两个子树,如下:
左子树:
2
/ \
4 5
前序遍历的结果是: [2,4,5]
中序遍历的结果是: [4,2,5]
右子树:
3
/ \
6 7
前序遍历的结果是: [3,6,7]
中序遍历的结果是: [6,3,7]
-
我们可以按照步骤3,将左右子树继续按照根节点继续拆分,可以总结出如下规律:
- 二叉树的根节点始终在
preorder[0]
- 二叉树可以按照根节点在
inorder
中的位置rootIndex
,将preorder
和inorder
拆分成左右两个子树的结果,如下:
左子树遍历结果:
preorder = preorder.slice(1, rootIndex + 1); inorder = inorder.slice(0, rootIndex);
右子树遍历结果:
preorder = preorder.slice(rootIndex + 1); inorder = inorder.slice(rootIndex + 1);
- 二叉树的根节点始终在
-
经过步骤4的分析,我们可以按照以下逻辑进行递归:
- 每次递归用
preorder[0]
的值生成一个根节点。 - 在通过
preorder[0]
找到其在inorder
中的位置rootIndex
,将preorder
和inorder
切割成两部分,分别进行下一层的递归。 - 将下层递归生成的左右子树,连接到当前根节点上。
- 递归完成时将当前根节点返回,供上一层递归连接。
preorder
和inorder
中的所有值都生成过节点之后,也就完成了整个二叉树的生成。
- 每次递归用
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
var buildTree = function (preorder, inorder) {
// 递归切割数组到最后,数组会为空,此时退出循环
if (preorder.length === 0) {
// 数组为空时,表示当前已经无节点需要生成,返回null
// 让上一层节点的left和right指针指向null
return null;
}
// 使用当前值创建一个节点,即为一个树的根节点
const root = new TreeNode(preorder[0]);
// 查找到当前根节点在数组中的位置
const rootIndex = inorder.findIndex((value) => preorder[0] === value);
// 将数组对应左子树的部分切割,向下递归
// 将当前根节点与已生成好的左子树连接
root.left = buildTree(
preorder.slice(1, rootIndex + 1),
inorder.slice(0, rootIndex),
);
// 将数组对应右子树的部分切割,向下递归
// 将当前根节点与已生成好的右子树连接
root.right = buildTree(
preorder.slice(rootIndex + 1),
inorder.slice(rootIndex + 1),
);
// 将根节点返回供上层节点连接
return root;
};