题目
给定两个整数数组 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 <= 3000inorder.length == preorder.length-3000 <= preorder[i], inorder[i] <= 3000preorder和inorder均 无重复 元素inorder均出现在preorderpreorder保证 为二叉树的前序遍历序列inorder保证 为二叉树的中序遍历序列
题解
解决这道题,首先我们要先知道二叉树的前序遍历,中序遍历,以及找出二者之间的关系,帮助我们构建出二叉树
前序遍历
先遍历根节点,再递归遍历左子树,最后递归遍历右子树
中序遍历
先递归遍历左子树,再遍历根节点,最后递归遍历右子树
中序遍历和前序遍历的关系
先序遍历:
pLeft指针指向根节点[pLeft + 1, pIndex - inLeft + pLeft]指向左子树[pIndex - inLeft + pLeft + 1, pRight ]指向右子树
中序遍历:
pIndex指针指向根节点[inLeft, pIndex - inLeft - 1 ]指向左子树[pIndex + 1, inRight ]指向右子树
代码
/**
* Definition for a binary tree node.
* function TreeNode(val, left, right) {
* this.val = (val===undefined ? 0 : val)
* this.left = (left===undefined ? null : left)
* this.right = (right===undefined ? null : right)
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
var buildTree = function(preorder, inorder) {
const pLen = preorder.length;
const inLen = inorder.length;
// 检测输入是否合法
if (pLen != inLen) {
throw new Error('input is invalid!');
}
const inorderMap = new Map();
// 设置inorder的映射,方便重建二叉树时的快速查找
for (let i = 0; i < inorder.length; i++) {
inorderMap.set(inorder[i], i);
}
// 执行递归构建树
return _buildTree(preorder, 0, pLen - 1, inorderMap, 0, inLen - 1);
/**
* @param preorder, 先序遍历数组
* @param preorderLeft, 先序遍历的左边界
* @param preorderRight, 先序遍历的右边界
* @param inorderMap, 中序遍历 值-索引 映射
* @param inorderLeft, 中序遍历的左边界
* @param inorderRight, 中序遍历的右边界
*/
function _buildTree(preorder, preorderLeft, preorderRight, inorderMap, inorderLeft, inorderRight) {
// 判断是否为空,
if (preorderLeft > preorderRight || inorderLeft > inorderRight) {
return null;
}
// 根节点值是先序遍历的第一个元素
const rootVal = preorder[preorderLeft];
const root = new TreeNode(rootVal);
// 根节点的索引
const pIndex = inorderMap.get(rootVal);
// 构建左子树
root.left = _buildTree(preorder, preorderLeft + 1, pIndex - inorderLeft + preorderLeft, inorderMap, inorderLeft, pIndex - 1);
// 构建右子树
root.right = _buildTree(preorder, pIndex - inorderLeft + preorderLeft + 1, preorderRight, inorderMap, pIndex + 1, inorderRight)
return root;
}
};