持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第25天,点击查看活动详情
前言
力扣练习第四天,拒绝思路老化。今天要练习的是重建二叉树
题目信息如下:
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。 假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
/**
* Definition for a binary tree node.
* function TreeNode(val) {
* this.val = val;
* this.left = this.right = null;
* }
*/
/**
* @param {number[]} preorder
* @param {number[]} inorder
* @return {TreeNode}
*/
/**
* Input: preorder = [3,9,20,15,7], inorder = [9,3,15,20,7]
* Output: [3,9,20,null,null,15,7]
* Input: preorder = [-1], inorder = [-1]
* Output: [-1]
*/
[3,9,20,null,null,15,7]转为二叉树如下图:
解法一
上次说过,遇到链表,二叉树不要怕,静下心来分析。我们知道,前序是根左右,中序是左根右,后序是左右根。已知前序和中序,推导出二叉树的结构。怎么推导呢?首先,我们确定根节点的位置,在前序中,根节点的位置是0,在中序中,根节点的位置设为index。那我们就不难得出,前序数组中,[1, index + 1),即为左子树的前序遍历,中序数组中,[0, index)即为左子树的中序遍历。左子树前序,中序出来了。右子树同理,[index + 1, length)为右子树的前序与中序。那就很明朗了,递归左子树与右子树,就可以得到我们的结果。
var buildTree = function(preorder, inorder) {
if(!preorder.length || !inorder.length){
return null
}
let tree = new TreeNode(preorder[0])
let index = inorder.indexOf(preorder[0])
tree.left = buildTree(preorder.slice(1,index+1),inorder.slice(0,index))
tree.right = buildTree(preorder.slice(index+1),inorder.slice(index+1))
return tree
};
解法二
第二种解法就比较难理解了,使用迭代法。具体怎么个迭代呢?我们需要知道,前序遍历中,对于连续的两个节点ab,有两种情况:
- b 是 a 的左节点
[3, 9, 8]中3,9的关系 - a 没有左儿子,并且 b 是 a 的某个祖先节点(或者 a 本身)的右儿子。
[3, 9, 20, null, 8]或[3, 9, 8]9 和 8 的关系
更详细可看官方题解
根据这个特点,我们基本可以确定迭代的规律(利用了栈和指针帮助我们简化算法,栈内默认存储根节点,指针默认指向中序遍历的首位):
-
index 指向栈顶节点,弹出栈顶节点并向右移动 index,并将当前节点作为最后一个弹出的节点的右儿子
-
index 不指向栈顶节点,我们将当前节点作为栈顶节点的左儿子;
无论哪一种情况,都将当前的节点入栈。
var buildTree = function(preorder, inorder) {
if (!preorder.length || !inorder.length) return null;
let root = new TreeNode(preorder[0]);
let stack = [root];
let index = 0;
for (let i = 1; i < preorder.length; i++) {
let preorderVal = preorder[i];
let node = stack[stack.length-1];
if(node.val !== inorder[index]) {
node.left = new TreeNode(preorderVal);
stack.push(node.left);
}else {
while(stack.length !==0 && stack[stack.length-1].val == inorder[index]) {
node = stack.pop();
index++;
}
node.right = new TreeNode(preorderVal);
stack.push(node.right);
}
}
return root
};