题目
没有重复元素这一点很重要,否则无法去定位。
解题
解题一:递归
// javascript
var buildTree = function(preorder, inorder) {
const inOrderMap = new Map();
// 构造哈希映射,帮助我们快速定位根节点
inorder.forEach((item, index) => inOrderMap.set(item, index));
return buildTreeHelper(preorder, 0, preorder.length - 1, inorder, 0, inorder.length - 1, inOrderMap);
};
var buildTreeHelper = function(preorder, preL, preR, inorder, inL, inR, inOrderMap) {
if (preL > preR || inL > inR) return null;
// 前序遍历中的第一个节点就是根节点, 把根节点建立出来
const root = new TreeNode(preorder[preL]);
// 在中序遍历中定位根节点
const inM = inOrderMap.get(root.val);
// 得到左子树中的节点数目
const leftSize = inM - inL;
// 递归地构造左子树,并连接到根节点
// 先序遍历中「从 左边界+1 开始的 leftSize」个元素就对应了中序遍历中「从 左边界 开始到 根节点定位-1」的元素
root.left = buildTreeHelper(preorder, preL + 1, preL + leftSize, inorder, inL, inM - 1, inOrderMap);
// 递归地构造右子树,并连接到根节点
// 先序遍历中「从 左边界+1+左子树节点数目leftSize 开始到 右边界」的元素就对应了中序遍历中「从 根节点定位+1 到 右边界」的元素
root.right = buildTreeHelper(preorder, preL + leftSize + 1, preR, inorder, inM + 1, inR, inOrderMap);
return root;
};
解题二:迭代
思路见 从前序与中序遍历序列构造二叉树-方法二,整个思路想起来和写起来都比较容易出错。
针对为右儿子找父亲的步骤,如果一个二叉树的所有节点都只有左子树,那么前序遍历和中序遍历是 reverse 的关系:
- 前序遍历:[ 根节点, [左子树] ]
- 后序遍历:[ [左子树], 根节点 ]
以下面的二叉树为例,前序遍历是 [8, 5, 4, 10],中序遍历是 [4, 5, 8, 10],由此可见,如果一个二叉树的所有节点都只有左子树,前序遍历 [8, 5, 4] 和 中序遍历 [4, 5, 8] 是 reverse 的关系,因而找到 10 的父亲是 8。
// javascript
var buildTree = function(preorder, inorder) {
if (preorder.length === 0) return null;
const root = new TreeNode(preorder[0]);
const stk = new Array();
stk.push(root);
let inorderIndex = 0;
for (let i = 1; i < preorder.length; i++) {
const curNode = new TreeNode(preorder[i]);
let prevNode = peek(stk);
// 上一个节点如果有左子树,curNode 是 prevNode 的左子树
if (prevNode.val !== inorder[inorderIndex]) {
prevNode.left = curNode;
} else {
// 上一个节点没有左子树,curNode 是 prevNode 或 prevNode的祖先节点的右子树
while (!isEmpty(stk) && peek(stk).val == inorder[inorderIndex]) {
prevNode = stk.pop();
inorderIndex++;
}
prevNode.right = curNode;
}
stk.push(curNode);
}
return root;
};
const isEmpty = (stk) => {
return stk.length === 0;
};
const peek = (stk) => {
return stk[stk.length - 1];
};