跟learnjiawa一起每天一道算法编程题,既可以增强对常用API的熟悉能力,也能增强自己的编程能力和解决问题的能力。算法和数据结构,是基础中的基础,更是笔试的重中之重。
- 不积硅步,无以至千里;
- 不积小流,无以成江海。
题目描述
牛客网剑指offer编程题第5题–重建二叉树,输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,3,4,5,6,7}和中序遍历序列{3,2,4,1,6,5,7},则重建二叉树并返回。
我的想法:
- 因为是树的结构,一般都是用递归来实现。假设最后一步,就是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();
}
}
}
控制台输出结果:
总结
递归思想很重要,涉及到二叉树时,一般都需要想到递归。
点击看剑指offer编程题打卡系列所有博客.
参考文献
[1]程杰. 大话数据结构. 北京:清华大学出版社, 2011.
更多
对我的文章感兴趣,持续更新中…
关注我,看其他系列博客,《跟凑弟弟一起修炼集合框架》、《Java多线程大闯关》、《Java IO流大闯关》。