题目描述
给定一棵树的前序遍历 preorder 与中序遍历 inorder。请构造二叉树并返回其根节点。
示例 1:
Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
Output: [3,9,20,null,null,15,7]
示例 2:
Input: preorder = [-1], inorder = [-1]
Output: [-1]
提示:
1 <= preorder.length <= 3000inorder.length == preorder.length-3000 <= preorder[i], inorder[i] <= 3000preorder和inorder均无重复元素inorder均出现在preorderpreorder保证为二叉树的前序遍历序列inorder保证为二叉树的中序遍历序列
思路如下:
- 前序遍历的顺序为根左右,中序遍历的顺序为左根右,所以
preorder[0]为当前子树根节点的值 - 查找该值在
inorder中的位置,其左边即为左子树中序遍历序列,右边为右子树中序遍历序列 - 获取到左右子树中序遍历后,因为子树前序遍历和中序遍历的结果只是顺序不同,但是序列长度是相同的,所以可以根据左子树中序遍历序列长度去
preorder获取左子树前序遍历序列,剩余部分即为右子树前序遍历序列 - 然后就可以通过根节点的值创建根节点,根据左右子树的前序、中序遍历序列递归创建左右子树
- 最后返回二叉树的根节点即可 如图:
代码实现
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
// 给了我们一个前序遍历数组和中序遍历数组,已知,前序遍历:根左右,中序遍历:左根右
// 根据遍历的特殊克制,前序遍历数组的第一个元素,是整个树的根节点,我们就获取到根节点的值
// 在终须遍历数组中,找到根节点的位置mid,我们就可以分割左右子树--左子树0~mid-1,右子树--mid+1~inorder.length-1
var buildTree = function(preorder, inorder) {
let map = new Map();
for(let i = 0; i < inorder.length; i++){
map.set(inorder[i],i)
}
const helper = function(pStart, pEnd, iStart, iEnd){
// 判断我们的前序遍历数组已经使用完毕
if(pStart > pEnd) return null;
// 获取根节点的值
let rootVal = preorder[pStart];
// 构造一个根节点
let root = new TreeNode(rootVal);
// 获取根节点在终须遍历数组中的索引位置,来分隔左右子树
let mid = map.get(rootVal);
// 计算左子树的节点个数,用来在前序遍历数组确定左子树结束的位置
let leftNum = mid - iStart;
// 递归的构建左子树
root.left = helper(pStart + 1, pStart + leftNum, iStart,mid -1);
// 递归的构建右子树
root.right = helper(pStart + leftNum + 1, pEnd, mid + 1 , iEnd);
return root;
}
return helper(0 , preorder.length -1, 0, inorder.length -1)
};