leetcode——重建二叉树

109 阅读2分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 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]转为二叉树如下图:

image.png

解法一

上次说过,遇到链表,二叉树不要怕,静下心来分析。我们知道,前序是根左右,中序是左根右,后序是左右根。已知前序和中序,推导出二叉树的结构。怎么推导呢?首先,我们确定根节点的位置,在前序中,根节点的位置是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
};