剑指 Offer 07. 重建二叉树
难度:中等
输入某二叉树的前序遍历和中序遍历的结果,请构建该二叉树并返回其根节点。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
示例 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]
限制:0 <= 节点个数 <= 5000
思路
1.首先明确前序遍历与中序遍历的特点,前序遍历是根左右,中序遍历是左根右。
2. 因此前序遍历数组中第一个结点一定是根节点,将这个根节点放在中序遍历中,该结点左边是左子树,结点右边是右子树。
3. 然后根据中序遍历左子树长度对应分割出前序遍历的左右子树后,再继续递归对左右子树继续重复步骤1,2,3,递归的边界条件就是左右子树为空或者是叶子结点。
代码如下
/**
* 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}
*/
var buildTree = function(preorder, inorder) {
return diGui(preorder, inorder);
};
function diGui(preorder, inorder) {
if(!preorder.length) return null; // 空,直接返回
let value = preorder[0], i; // 利用根节点在前序遍历序列中第一位的特性
let root = new TreeNode(value);
if(preorder.length === 1) return root; // 叶子结点
// 在中序遍历序列中找到前序遍历序列中的第一位的位置
for(i = 0; i < inorder.length; i++) {
if(value === inorder[i]) break;
}
// 根据下标,分别将中序遍历序列,和前序遍历序列给分割成左右两个子序列
let leftInorder = inorder.slice(0, i), rightInorder = inorder.slice(i + 1);
let leftPreorder = preorder.slice(1, leftInorder.length + 1), rightPreorder = preorder.slice(leftInorder.length + 1);
// 让该结点左右子树继续递归
root.left = diGui(leftPreorder, leftInorder);
root.right = diGui(rightPreorder, rightInorder);
return root;
}
时间和空间复杂度如图