返回
剑指 Offer II 070. 从前序与中序遍历序列构造二叉树
前端
2023-09-17 06:55:01
如何根据前序和中序遍历序列构造二叉树
在计算机科学领域,二叉树 是一种重要的数据结构,它由一个根节点和两个子树(左子树和右子树)组成。前序遍历 和中序遍历 是遍历二叉树的两种常见方法。
前序遍历从根节点开始,依次访问每个节点及其左子树和右子树。而中序遍历从根节点的左子树开始,依次访问每个节点,然后访问根节点,最后访问根节点的右子树。
给定前序和中序遍历序列,我们如何构造对应的二叉树呢?别担心,让我们一步步来分解这个过程。
算法步骤
-
确定根节点: 从前序遍历序列中取出第一个元素,它就是二叉树的根节点。
-
查找根节点在中序遍历序列中的位置: 在中序遍历序列中找到根节点的值,它的位置将把序列分成两个部分:左子树和右子树。
-
递归构造子树: 使用相同的方法,对左子树和右子树分别进行前序和中序遍历。对于左子树,使用前序遍历序列的第二个元素到根节点位置之间的元素,以及中序遍历序列根节点左侧的部分。对于右子树,使用前序遍历序列根节点位置之后的元素,以及中序遍历序列根节点右侧的部分。
代码示例
// 创建二叉树节点
class TreeNode {
constructor(val) {
this.val = val;
this.left = null;
this.right = null;
}
}
/**
* 根据前序和中序遍历序列构造二叉树
* @param {number[]} preorder 前序遍历序列
* @param {number[]} inorder 中序遍历序列
* @returns {TreeNode} 二叉树的根节点
*/
const buildTree = (preorder, inorder) => {
// 创建哈希表存储中序遍历序列元素的位置
const inorderMap = new Map();
for (let i = 0; i < inorder.length; i++) {
inorderMap.set(inorder[i], i);
}
// 递归函数构造二叉树
const buildTreeHelper = (preStart, preEnd, inStart, inEnd) => {
// 前序遍历序列范围为空,返回 null
if (preStart > preEnd) {
return null;
}
// 取前序遍历序列的第一个元素作为根节点值
const rootVal = preorder[preStart];
// 在中序遍历序列中查找根节点位置
const rootIndex = inorderMap.get(rootVal);
// 创建根节点
const root = new TreeNode(rootVal);
// 递归构造左子树
root.left = buildTreeHelper(
preStart + 1,
preStart + rootIndex - inStart,
inStart,
rootIndex - 1
);
// 递归构造右子树
root.right = buildTreeHelper(
preStart + rootIndex - inStart + 1,
preEnd,
rootIndex + 1,
inEnd
);
// 返回根节点
return root;
};
// 调用递归函数构造二叉树
return buildTreeHelper(0, preorder.length - 1, 0, inorder.length - 1);
};
动画演示
为了更直观地理解这一过程,这里有一个动画演示:
[动画演示链接]
常见问题解答
1. 如何确定根节点?
根节点是前序遍历序列的第一个元素。
2. 如何找到根节点在中序遍历序列中的位置?
在中序遍历序列中,根节点的值将序列分成左右两部分。根节点位于这两部分的连接处。
3. 为什么需要哈希表?
哈希表用于快速查找中序遍历序列中每个元素的位置。这可以大大提高算法的效率。
4. 算法的复杂度是多少?
算法的时间复杂度为 O(n),其中 n 是二叉树中的节点数。
5. 有没有其他构造二叉树的方法?
除了前序和中序遍历序列,还可以使用其他遍历顺序,例如后续遍历和层序遍历来构造二叉树。