从中序与后序遍历序列构造二叉树

力扣链接

B站力扣官方视频讲解(使用Map的解法)

B站讲解的这道题是,从中序和前序遍历序列构造二叉树,与当前这道题是一类的,两道题可以一起写,一起看,巩固一下。


目前小编还没有学习map,所以本文章只会用指针的方式去解答本道题,让不会map的小伙伴,也知道怎么做。


目录

想要解答本题,你一定要知道的是: 

解题思路(使用递归):

1.倒序遍历postorder数组,用postIndex表示当前访问的元素,postIndex初始值==postorder的长度-1,从数组中得到当前根节点Root并创建,然后postIndex--

2.在inorder数组中找到root节点

3.重复执行第一点,获得新的根节点root,然后在inorder数组的区间

代码书写:

1.由于题目接口数量不够,所以我们新创建一个方法,来构建树

2.先把postIndex指向数组末位置,等一下好遍历递归,与此同时,返回一个初始的子方法,_buildTree.(因为实际上我们是在这个方法里面创建树的)

3.回到_buildTree方法,递归创建root的右子树,左子树

4.findRootInOrder方法的实现:

5.整体代码:


题目:

下面以下图的例子作为讲解:

题目给定两个有效的中序和后序遍历的二叉树,可以确定唯一的这颗二叉树。


想要解答本题,你一定要知道的是: 

1.在中序遍历的二叉树序列中,某一个节点的左子树一定在该节点的左边(如果有左树)
例如,节点20的左子树是15,在inorder[2],是inorder[3]=20的左边

2.后序遍历的序列的末尾元素一定是此树的根节点

3.由于后序遍历按照的是:左子->右子->根

所以如果我们尝试对postorder倒着遍历(3,20,7....),那么访问顺序就是:

根->右子树->左子树


解题思路(使用递归):

1.倒序遍历postorder数组,用postIndex表示当前访问的元素postIndex初始值==postorder的长度-1从数组中得到当前根节点Root并创建,然后postIndex--

2.在inorder数组中找到root节点

注意:

此时,我们可以在inorder数组中找到Root所在下标inorderIndex,这是可以通过inorderIndex下标把inorder数组一分为二

3.重复执行第一点,获得新的根节点root,然后在inorder数组的区间

[inorderIndex-1,inorderIndex.length-1]寻找root节点,如果找到,那么Root.right==root,如果没有找到,那么Root.right==null

代码书写:

1.由于题目接口数量不够,所以我们新创建一个方法,来构建树

2.先把postIndex指向数组末位置,等一下好遍历递归,与此同时,返回一个初始的子方法,_buildTree.(因为实际上我们是在这个方法里面创建树的)

3.回到_buildTree方法,递归创建root的右子树,左子树

findRootInOrder方法(找到inorder数组中,对应root下标)等一下再实现,先把框架搭好

上面代码缺少一个递归终止条件,是什么呢?

如果按照上面的程序递归,begin,end会这样变

{begin,end}=[0,4] [2,4] [4,4] [5,4].........

哎,发现了吧,此时begin竟然大于end,这是不符合常理的,这实际上就说明,右树的创建已经完成了,可以去创建左树了。

因此递归结束条件也就很简单了:

4.findRootInOrder方法的实现:

5.整体代码:

class Solution {

    //用begin和end来管理inorder数组--都是int类型
    //用postIndex来管理postorder数组--int类型,注意postIndex必须定义为成员变量
    private int postIndex;//成员变量,默认初始化为0
    private TreeNode _buildTree(int[] inorder,int[] postorder,int begin,int end){

        if(begin>end)return null;//返回一个空树
        TreeNode root=new TreeNode(postorder[postIndex]);//创建当前的根节点
        int inIndex=findRootInOrder(inorder,begin,end,postorder[postIndex]);//找到把inorder数组一分为二的根节点下标
        postIndex--;//让指针指向下一个根节点,也就是当前root节点的右子树(如果有)

        root.right=_buildTree(inorder,postorder,inIndex+1,end);//右半区间
        root.left=_buildTree(inorder,postorder,begin,inIndex-1);//左半区间

        return root;//返回创建好的根节点

    }

    public TreeNode buildTree(int[] inorder, int[] postorder) {

        this.postIndex=postorder.length-1;

        return _buildTree(inorder,postorder,0,inorder.length-1);//begin和end是闭区间
    }

    private int findRootInOrder(int[] inorder,int begin,int end,int key){
        for (int i = begin; i <=end ; i++) {
            if(inorder[i]==key)return i;//找到,返回下标
        }
        return -1;//这句话一定不会执行,只是为了让编译器不报错,你返回100个w,都没问题
        //因为begin,end闭区间如果找不到,递归条件会返回null
    }
}

  • 19
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值