题目:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如:前序遍历序列{ 1, 2, 4, 7, 3, 5, 6, 8}和中序遍历序列{4, 7, 2, 1, 5, 3, 8,6},重建出下图所示的二叉树并输出它的头结点。
首先要了解什么是前序遍历、中序遍历和后序遍历,这个概念我已经在《算法》读书笔记的《6、二分搜索树(上)》中详细介绍了。
定义节点类型
class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) {
val = x;
}
}
代码实现
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
TreeNode root=reConstructBinaryTree(pre,0,pre.length-1,in,0,in.length-1);
return root;
}
//前序遍历{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6}
private TreeNode reConstructBinaryTree(int [] pre,int startPre,int endPre,int [] in,int startIn,int endIn) {
//递归停止条件,因为每次都取左孩子和右孩子,这个指向前序或者中序数组一头一尾的索引,尾小于头的时候,就要停止递归了
if(startPre>endPre||startIn>endIn)
return null;
//左孩子或者右孩子的根节点
TreeNode root=new TreeNode(pre[startPre]);
//pre数组第一个元素为根节点root
//在in数组中找到root位置,那么前面为左孩子中序遍历(假设n个),后面为右孩子中序遍历(假设m个)
//那么根据这个n和m,就能在pre数组中找到左孩子前序遍历和右孩子前序遍历
//那么递归的时候,root.left就是【左孩子前序遍历,左孩子中序遍历】,root.right就是【右孩子前序遍历,右孩子中序遍历】
//这样一直到叶子节点,停止
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;
}
}
重构过程
前序遍历:12473568
中序遍历:47215386
- 前序遍历中的第一个值为树根
- 树根在中序遍历中的位置,左侧为左子树的中序遍历结果(472),右侧为右子树的中序遍历结果(5386)
- 在前序遍历中,左子树的前序遍历结果为(247),右子树的前序遍历结果为(3568)
- 则2为左子树的树根,3为右子树的树根
- 重复上述操作直至结束