Java版牛客网剑指offer编程题第4题--重建二叉树

跟learnjiawa一起每天一道算法编程题,既可以增强对常用API的熟悉能力,也能增强自己的编程能力和解决问题的能力。算法和数据结构,是基础中的基础,更是笔试的重中之重。

  • 不积硅步,无以至千里;
  • 不积小流,无以成江海。

点击看剑指offer编程题打卡系列所有博客.

题目描述

牛客网剑指offer编程题第5题–重建二叉树,输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。

例如输入前序遍历序列{1,2,3,4,5,6,7}和中序遍历序列{3,2,4,1,6,5,7},则重建二叉树并返回。
牛客网剑指offer编程题第4题

我的想法:

  • 因为是树的结构,一般都是用递归来实现。假设最后一步,就是root的左右子树都已经重建好了,那么我只要考虑将root的左右子树安上去即可。
  • 根据前序遍历的性质,第一个元素必然就是root,那么下面的工作就是如何确定root的左右子树的范围。
  • 根据中序遍历的性质,root元素前面都是root的左子树,后面都是root的右子树。那么我们只要找到中序遍历中root的位置,就可以确定好左右子树的范围。
  • 正如上面所说,只需要将确定的左右子树安到root上即可。另外递归要注意出口哦

提示:

不是特别清楚或者忘记了什么是二叉树的前序遍历和中序遍历的小童鞋可以先看看我在后面代码测试中写的Node类和BinaryTree类,里面自己创建了一个节点类,又利用该节点创建了一个二叉树类,并给该二叉树写了前序遍历和中序遍历的方法,可以动手打一下就明白了,主要就是一个递归思想哦。

解题方法

    public static BinaryTree reConstructBinaryTree(int [] pre, int [] in) {
        Node root = reConstructBinaryTree(pre, 0, pre.length-1, in, 0 , in.length-1);
        BinaryTree binaryTree = new BinaryTree();
        binaryTree.setRoot(root);
        return binaryTree;
    }

    private static Node reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn){
        //出口条件
        if(startPre>endPre||startIn>endIn)
            return null;
		//根据前序遍历的性质,第一个元素必然就是root
        Node root = new Node(pre[startPre]);
        for(int i=startIn;i<=endIn;i++){
            if(in[i]==pre[startPre]){
            //root元素前面都是root的左子树,后面都是root的右子树
               root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
               root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
               break;
            }
        }
        return root;
    }

代码测试

package com.learnjiawa.jzoffer;


import javax.swing.tree.TreeNode;

/**
 * @author zouhuayu
 * 2019-12-03-9:40
 */
public class Solution4 {
    public static void main(String[] args) {
        //先创建一个二叉树
        BinaryTree tree = new BinaryTree();
        //创建需要的节点
        Node root = new Node(1);
        Node node2 = new Node(2);
        Node node3 = new Node(3);
        Node node4 = new Node(4);
        Node node5 = new Node(5);
        Node node6 = new Node(6);
        Node node7 = new Node(7);

        //手动建立联系
        root.setLeft(node2);
        root.setRight(node5);
        node2.setLeft(node3);
        node2.setRight(node4);
        node5.setLeft(node6);
        node5.setRight(node7);

        tree.setRoot(root);

        System.out.println("前序遍历");
        tree.preOrder();
        System.out.println("中序遍历");
        tree.midOrder();

        int[] pre = {1,2,3,4,5,6,7};
        int[] in = {3,2,4,1,6,5,7};
        BinaryTree resultTree = reConstructBinaryTree(pre, in);
        System.out.println("测试返回二叉树的前序遍历");
        resultTree.preOrder();
        System.out.println("测试返回二叉树的中序遍历");
        resultTree.midOrder();
    }

    public static BinaryTree reConstructBinaryTree(int [] pre, int [] in) {
        Node root = reConstructBinaryTree(pre, 0, pre.length-1, in, 0 , in.length-1);
        BinaryTree binaryTree = new BinaryTree();
        binaryTree.setRoot(root);
        return binaryTree;
    }

    private static Node reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn){
        //出口条件
        if(startPre>endPre||startIn>endIn)
            return null;

        Node root = new Node(pre[startPre]);
        for(int i=startIn;i<=endIn;i++){
            if(in[i]==pre[startPre]){
               root.left=reConstructBinaryTree(pre,startPre+1,startPre+i-startIn,in,startIn,i-1);
               root.right=reConstructBinaryTree(pre,i-startIn+startPre+1,endPre,in,i+1,endIn);
               break;
            }
        }
        return root;
    }

}

//Definition for binary tree
//定义一个BinaryTree 二叉树
//根节点,set方法,两种遍历方法
class BinaryTree{
    Node root;

    public void setRoot(Node root) {
        this.root = root;
    }
    //前序遍历
    public void preOrder(){
        if(root != null){
            root.preOrder();//调用节点的前序遍历方法
        }else{
            System.out.println("根节点为空");
        }
    }
    //中序遍历
    public void midOrder(){
        if(root != null){
            root.midOrder();//调用节点的后序遍历方法
        }else{
            System.out.println("根节点为空");
        }
    }
}

class Node{
    //编写节点类
//id, name, left, right, 构造方法,getsetter,重写toString(),两种遍历方法
    int id;
    Node left;
    Node right;

    public Node(int id){
        this.id = id;
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }


    public Node getLeft() {
        return left;
    }

    public void setLeft(Node left) {
        this.left = left;
    }

    public Node getRight() {
        return right;
    }

    public void setRight(Node right) {
        this.right = right;
    }

    @Override
    public String toString() {
        return "Node{" +
                "id=" + id +
                ", left=" + left +
                ", right=" + right +
                '}';
    }

    //前序遍历
    public void preOrder(){
        //递归输出根节点、左节点、右节点
        System.out.println(this);
        if(this.left != null){
            this.left.preOrder();
        }
        if(this.right != null){
            this.right.preOrder();
        }
    }
    //中序遍历
    public void midOrder(){
        //递归输出左节点、根节点、右节点
        if(this.left != null){
            this.left.midOrder();
        }
        System.out.println(this);
        if(this.right != null){
            this.right.midOrder();
        }
    }

}

控制台输出结果:
no4测试结果图

总结

递归思想很重要,涉及到二叉树时,一般都需要想到递归。
点击看剑指offer编程题打卡系列所有博客.

参考文献

[1]程杰. 大话数据结构. 北京:清华大学出版社, 2011.

更多

对我的文章感兴趣,持续更新中…
关注我,看其他系列博客,《跟凑弟弟一起修炼集合框架》、《Java多线程大闯关》、《Java IO流大闯关》。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值