链接:来源:牛客网
题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
思路解析
:
1,首先,需要知道什么是前序遍历,什么是中序遍历。至于什么是树。树(Tree-java实现)
- 前序遍历:
遍历规则:若二叉树是空树,则空操作返回,否则先访问根结点,然后前序遍历左子树,在前序遍历右子树。(根—》左—》右)
- 中序遍历:
遍历规则:中序遍历根节点的左子树,然后访问根节点,最后在是右子树。(顺序:左—》中—》右)
- 后续遍历:
遍历规则:若树是空,则返回空操作,否则就是从左到右先叶子节点后根节点的顺序。(左——》右——》根)
代码:
//前序遍历法,递归实现
static void preOrderTraverse(TreeNode node){
if(node==null){
return;
}
System.out.print(node.getValue()+"->");
preOrderTraverse(node.getLeft());
preOrderTraverse(node.getRight());
}
//中序遍历,递归实现
static void InOrderTraverse(TreeNode node){
if(node==null){
return;
}
InOrderTraverse(node.getLeft());
System.out.print(node.getValue()+"->");
InOrderTraverse(node.getRight());
}
//后序遍历
static void PostOrderTraver(TreeNode node){
if(node == null){
return;
}
PostOrderTraver(node.getLeft());
PostOrderTraver(node.getRight());
System.out.print(node.getValue()+"->");
}
题目(再来一遍防止遗忘):输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
言归正传,开始解题。从前序遍历的规则可以很容易的得到根节点。即:第一个遍历节点,因此1便是根节点
。而通过中序遍历我们可以知道,它的遍历规则是:左—》中—》右
即:根节点在中间,由根节点将树分为了左右子树。即左子树为:{4,7,2},右子树为{5,3,8,6}由此我们可以由1将中序遍历中的左右子树分割出来了。
这里我们可以发现,我们通过前序遍历找到根节点和中序遍历找到左右子树
,是不是也可以对左右子树进行相同的操作来分割出子节点的左右孙子节点呢?肯定是的!这就是递归的思想来解决了吧!
当然这个巧妙地方法其实不是我原创的【dogo】
package Offer;
import java.util.Arrays;
public class TreeDemo {
public static void main(String[] args) {
//二叉树前中序遍历
int[] pre = new int[]{1,2,4,7,3,5,6,8};
int[] in = new int[]{4,7,2,1,5,3,8,6};
System.out.print("前序: ");
preOrderTraverse(reConstructBinaryTree(pre,in));
System.out.println();
System.out.print("中序: ");
InOrderTraverse(reConstructBinaryTree(pre,in));
}
public static TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if(pre.length==0&&in.length==0){
return null;
}
//前序遍历序列{1,2,4,7,3,5,6,8} 中序遍历序列{4,7,2,1,5,3,8,6}
//由前序获得根节点
TreeNode treeRoot = new TreeNode(pre[0]);
//在通过中序遍历来分割左右子树
for(int i = 0;i<in.length;i++){
if(pre[0] == in[i]){
//当找到中序遍历中根节点的位置时,开始进行子树递归的分割
//递归的进行左右子树的根,左结点,右结点的分割
//Arrays.copyOfRange(T[ ] original,int from,int to)
//将一个原始的数组original,从下标from开始复制,复制到上标to,生成一个新的数组。
//注意这里包括下标from,不包括上标to。
//进行左子树的构建和分割
treeRoot.left = reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
//进行右子树的构建和分割
treeRoot.right = reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,pre.length),Arrays.copyOfRange(in,i+1,in.length));
}
}
return treeRoot;
}
//前序遍历法,递归实现
static void preOrderTraverse(TreeNode node){
if(node==null){
return;
}
System.out.print(node.getValue()+"->");
preOrderTraverse(node.getLeft());
preOrderTraverse(node.getRight());
}
//中序遍历,递归实现
static void InOrderTraverse(TreeNode node){
if(node==null){
return;
}
InOrderTraverse(node.getLeft());
System.out.print(node.getValue()+"->");
InOrderTraverse(node.getRight());
}
//后序遍历
static void PostOrderTraver(TreeNode node){
if(node == null){
return;
}
PostOrderTraver(node.getLeft());
PostOrderTraver(node.getRight());
System.out.print(node.getValue()+"->");
}
}