题目
解题思路
- 先序遍历顺序:根左右;
- 中序遍历顺序:左根右;
- 根据先序得到根节点位置;
- 根据根节点位置 结合中序,得到左右子树;
- 先序遍历、中序遍历中左右子树个数相同,可求出先序、中序中左右子树的下标;
- 利用 map 求出根节点的位置,map始终存的是中序遍历元素(包括 leetcode106也是);
- 画图!画图!画图!画图可清楚的看出来左右子树的下标。
画图求左右子树下标
根据左右子树在先序和中序遍历中的个数相同,得出:
x - (preLeft + 1) = pIndex - 1 - inLeft
preRight - y = inRight - (pIndex + 1)
则
x = pIndex - inLeft + preLeft
y = preRight - inRight + pIndex + 1
根节点的值 rootVal = postOrder(postRight)
构造根节点 root = new TreeNode(rootVal)
根节点在中序遍历中的下标 pIndex = map.get(rootVal)
根据这些关键点,递归遍历构造出二叉树,最后 return root 即可。
Code part
var buildTree = function(preorder, inorder) {
let preLen = preorder.length
let inLen = inorder.length
if(preLen !== inLen) return
let map = new Map()
for(let i=0;i<inLen;i++){
map.set(inorder[i],i)
}
//遍历左右子树,构造二叉树
return build(preorder,0,preLen-1,map,0,inLen-1)
};
function build(preorder,preLeft,preRight,map,inLeft,inRight){
if(preLeft > preRight || inLeft > inRight){
return null
}
let rootVal = preorder[preLeft]
let root = new TreeNode(rootVal)
let pIndex = map.get(rootVal) //中序根节点的位置
//先序遍历中的左子树区间 & 中序遍历中的左子树区间
root.left = build(preorder,preLeft+1,pIndex-inLeft+preLeft,map,inLeft,pIndex-1)
//先序遍历中的右子树区间 & 中序遍历中的右子树区间
root.right = build(preorder,pIndex-inLeft+preLeft+1,preRight,map,pIndex+1,inRight)
return root
}
注意点
map中存的是中序遍历的节点,因为要利用根节点在中序遍历中的特殊位置,结合左右子树节点个数相同的点,求出左右子树的下标。
build参数中为左右子树的起始、结束下标位置。