105. 从前序与中序遍历序列构造二叉树
给定一棵树的前序遍历 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 <= 3000
- inorder.length == preorder.length
- -3000 <= preorder[i], inorder[i] <= 3000
- preorder 和 inorder 均无重复元素
- inorder 均出现在 preorder
- preorder 保证为二叉树的前序遍历序列
- inorder 保证为二叉树的中序遍历序列
递归遍历
思路
这道题目中我们要跟据一棵树的前序遍历和中序遍历来还原树
那么我们可以用递归的思想来做
条件一:首先我们可以通过前序遍历来找到树的根节点root的值
条件二:接下来我们可以在后续遍历中找到root节点的位置信息rootIndex
条件三:无论左子树的前序遍历还是中序遍历,他们的数量一定是相同的
从以上两个条件中,我们可以得到一个信息:
前序遍历 [root,leftChildPre,rightChildPre]
- leftChildPre:左子树的前序遍历
- rightChildPre:右子树的前序遍历
中序遍历 [leftChildOrder,root,rightChildOrder]
- leftChildOrder:左子树的中序遍历
- rightChildOrder:右子树的中序遍历
那么我们就可以这么处理:
- 用左子树的前序遍历leftChildPre和中序遍历leftChildOrder来生成左子树
- 用右子树的前序遍历rightChildPre和中序遍历rightChildOrder来生成右子树
- 然后把左子树和右子树分别拼接在root节点上
至此,思路就完毕了
具体实现看代码注释
var buildTree = function (preorder, inorder) {
//通过前序遍历的首节点来获取根节点
var rootNode = preorder[0]
//通过findIndex来获取中序遍历中rootNode的位置信息
var rootIndex = inorder.findIndex(item => item === rootNode)
//根据rootIndex来获取左子树的前序遍历结果
var leftChildPre = preorder.slice(1, 1 + rootIndex)
//同理获取右子树的前序遍历结果
var rightChildPre = preorder.slice(1 + rootIndex)
//根据rootIndex来获取左子树的中序遍历结果
var leftChildOrder = inorder.slice(0, rootIndex)
//同理获取右子树的中序遍历结果
var rightChildOrder = inorder.slice(1 + rootIndex)
//最后声明两个变量来保存左子树和右子树的还原结果
var leftChildRoot, rightChildRoot
//重点,递归的出口
//如果左子树的节点数量小于等于1,那么只有一个节点或者为null
if(leftChildPre.length <= 1){
//如果左子树有节点则直接生成一颗单节点的树 , 否则为null
leftChildRoot = leftChildPre.length > 0 ? new TreeNode(leftChildPre[0]) : null
}else{
//如果节点数量大于1则需要继续递归处理
leftChildRoot = buildTree(leftChildPre, leftChildOrder)
}
//同上
if(rightChildPre.length <= 1){
rightChildRoot = rightChildPre.length > 0 ? new TreeNode(rightChildPre[0]) : null
}else{
rightChildRoot = buildTree(rightChildPre, rightChildOrder)
}
//最后只需要把左右子树衔接在根节点下即可
var root = new TreeNode(rootNode, leftChildRoot, rightChildRoot)
return root
};