根据中序遍历和后续遍历(前序遍历)构造二叉树

根据中序遍历和后续遍历(前序遍历)构造二叉树

首先说说递归:对于大部分人而言递归总是那么难,因为它的过程比较抽象和复杂,但是说到底递归也是分治法的思想只要我们求得
相同子问题的解法那么对每个子问题求解并且合并就是我们整个递归的过程
我们举个例子:
假如一个树的
前序遍历 preorder = [3,9,20,15,7]
中序遍历 inorder = [9,3,15,20,7]
后序遍历 postorder = [9,15,7,20,3]

那么我们可以这样拆解问题:
我们首先分析前中序遍历:
前序遍历的的第一个节点往往是我们的根节点
root=3
而后我们根据中序遍历可以把前序遍历分为两部分,把中序遍历也分为两部分,作为下层使用的前中序数组
我们可以得到在中序遍历中3处在1下标
那么分割后:
leftinorder = [9]//左子树中序
leftpreorder = [9]//左子树前序
rightinorder = [15,20,7]//右子树中序
rightpreorder = [20,15,7]//右子树前序

看到这里大家肯定有点明白但是还是不知道代码如何写那么我们来看看规律:
首先我们找到了3在中序遍历中的1处所以看看如下计算方法(不要问为什么这就是规律总结而来的)
i//这个变量用来记录中遍历root的下标此时i==1
leftinorder=Arrays.copyOfRange(inorder,0,i);//这个是java自带的数组工具作用是截取原数组形成新数组(左闭右开)
leftpreorder=Arrays.copyOfRange(preorder,1,i+1);
rightinorder=Arrays.copyOfRange(inorder,i+1,inorder.length);
rightpreorder=Arrays.copyOfRange(preorder,i+1,preorder.length);

//以上就是我们每层的前中序诞生逻辑
然后我们看看每层怎么取root
刚才说过每次进来取前序第一个元素为根节点(前序遍历特点)
也就是说我们每层都要进行这样一次操作: TreeNode root=new TreeNode(preorder[0]);

这样每层根节点就确定了,也就意味着我们每层的节点都有了(我们的二叉树可以分解为很多个二叉树,也就意味着每个节点都可作为根)
那么接下来我们应该把每个根都连接起来也就是合并子问题让它形成树:
root.left=递归(leftinorder,leftpreorder);
root.right=递归(rightinorder,rightpreorder);
这样问题就愉快的解决了上完整代码:

import java.util.Arrays;
class Solution {
    public TreeNode buildTree(int[] preorder, int[] inorder) {
        if(preorder==null||inorder==null||preorder.length==0||inorder.length==0){
            return null;
        }
        //生成一个根节点
        TreeNode root=new TreeNode(preorder[0]);
        int i=0;//用来记录每次中序遍历找到的根的位置
        for(;i<inorder.length;i++){
            if(inorder[i]==preorder[0]){
                break;
            }
        }
        //创建左子树
        int[] leftPre= Arrays.copyOfRange(preorder,1,i+1);
        int[] leftIn=Arrays.copyOfRange(inorder,0,i);
        //创建右子树
        int[] rightPre= Arrays.copyOfRange(preorder,i+1,preorder.length);
        int[] rightIn=Arrays.copyOfRange(inorder,i+1,inorder.length);
        //左子树
        root.left= buildTree(leftPre,leftIn);
        //右子树
        root.right= buildTree(rightPre,rightIn);
        return root;
    }
   
}

那后序和中序呢:

其实就是生成每层后序的规律有所差别
然后一毛一样

leftpostorder = [9];
rightpostorder = [15,7,20];
总结规律:
leftpostorder=Arrays.copyOfRange(postorder,0,i);
rightpostorder=Arrays.copyOfRange(postorder,i,postorder.length-1);

是不是很好想呢。。。。。上代码

import java.util.Arrays;
class Solution {
    public TreeNode buildTree(int[] inorder, int[] postorder) {
        if(inorder==null||postorder==null||inorder.length==0||postorder.length==0){
            return null;
        }
        //将后序遍历的最后一个节点取出为根
        TreeNode root=new TreeNode(postorder[postorder.length-1]);
        int i=0;//记录中序遍历根的位置
        for(;i<inorder.length;i++){
            if(postorder[postorder.length-1]==inorder[i]){
                break;
            }
        }
        //构造左子树
        int[] leftIn=Arrays.copyOfRange(inorder,0,i);
        int[] leftPost=Arrays.copyOfRange(postorder,0,i);
        //构造右子树
        int[] rightIn=Arrays.copyOfRange(inorder,i+1,inorder.length);
        int[] rightPost=Arrays.copyOfRange(postorder,i,postorder.length-1);
        //左子树
        root.left=buildTree(leftIn,leftPost);
        //右子树
        root.right=buildTree(rightIn,rightPost);
        return root;
    }
}
  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值