剑指offer[4]——重建二叉树

题目描述

输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。

先序遍历是按照中——左——右的方式对二叉树进行遍历,由这种遍历方式我们可以很容易理解现需遍历的第一个数字是根节点的值。

image-20200304113631108

比如说这个二叉树的线序遍历就是1-2-4-7-3-5-6-8,第一个数字就是根节点的值。

而中序遍历,顾名思义,就是按照左——中——右的顺序进行遍历。

上图是我画的一个示意图,首先由先序遍历得知根节点的值为1,又因为题目中说输入的前序遍历和中序遍历的结果中都不含重复的数字,所以我们可以断定中序遍历序列中的第四位1位根节点,右中序遍历的性质可知,1左边的数字为根节点左子树所有节点的值,1右边为根节点右子树所有节点的值。

我们现在思考一下,既然我们现在这样可以确定出根节点的值,那我们能不能确定出根节点左右子树根节点的值呢。其实很简单,我们把中序遍历分为了两部分(【4,7,2】与【5,3,8,6】),那我们也可以将先序遍历分为两部分(【2,4,7】与【3,5,6,8】),同样也为左右子树所有节点的值。那我们先拿【4,7,2】与【2,4,7】分析,由先序遍历性质,我们是不是可以知道2为左子树根节点的值呢,其实道理和上面讲的是一样的。

分析到这里,大家应该明白可以用什么方法去做这个题目了,用递归是比较简单的一种方法,算法实现如下:

/* function TreeNode(x) {
    this.val = x;
    this.left = null;
    this.right = null;
} */
function reConstructBinaryTree(pre, vin)
{
    let head = new TreeNode();
    function tree(head, pre, vin){
        head.val = pre[0];
        const index = vin.indexOf(pre[0]);
        if(index!=0){
            head.left = new TreeNode();
            tree(head.left, pre.slice(1,index+1), vin.slice(0, index));
        }
        if(index!=vin.length-1){
            head.right = new TreeNode();
            tree(head.right, pre.slice(index+1, pre.length), vin.slice(index+1, vin.length));
        }
    }
    tree(head, pre, vin);
    return head;
}

猜你喜欢

转载自www.cnblogs.com/Jacob98/p/12408622.html