题目描述:
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
题目解析:
1.前序遍历:
前序遍历的规则:先根节点,后左子树,再右子树
2.中序遍历:
中序遍历的规则:先左子树,后根节点,再右子树
3.求重构二叉树:
根据二叉树,应当想当应该使用递归方式,递归的画寻找规律,根据前序遍历,中序遍历的规则,可以得到下面的图示
- 递归函数的设计:
- 应当存在前序数组,起始位,结束位,中序数组,起始位,结束位
- 根据前序起始位判断根节点,根据中序定位到根节点,然后得到左子树部分,右子树部分
- 左子树可定位新的起始位,新的结束位,自然也可以得到中序起始位,结束位,可以持续递归
- 递归结束条件的选择很重要:
- 每次左子树的根节点都是上一次前序根节点的下一位,当起始位大于结束位时,可以判断无此子树,返回为空;
- 当在中序定位不到根节点时,可以判断当前为叶子节点,返回当前节点;
- 注意点:
- 每次起始位和结束位的定位应该考虑坐标在移动,因此如何统一左子树的参数计算和右子树的参数
- 可以每次赋值左子树,右子树为新的函数,一路减少数组长度,到零界点
- 可以每次通过计算上一次的前序根节点坐标,中序定位的根节点坐标,结束位等参数进行判断
- 每次起始位和结束位的定位应该考虑坐标在移动,因此如何统一左子树的参数计算和右子树的参数
代码:
public class Solution {
public static void main(String[] args){
Solution so=new Solution();
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.println(so.reConstructBinaryTree(pre, in));
}
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
return rebuild(pre,0,pre.length,in,0,in.length);
}
//前序数组,前序起始位,前序结束位,后序数组,后序起始位,后序结束位
private TreeNode rebuild(int [] pre,int prestart ,int preend ,int[] in ,int instart,int inend){
//递归结束条件,叶子节点的左右节点为null;
if(prestart > preend || instart>= inend){
return null;
}
TreeNode node=new TreeNode(pre[prestart]);
//定位根节点
for(int i=instart;i<inend;i++){
if(in[i]==pre[prestart]){
//递归左子树:前序起始位+1,前序起始位+中序定位根节点的长度,中序起始位不变,中序结束位为定位到的坐标
node.left=rebuild(pre, prestart+1 , prestart+(i-instart), in ,instart,i);
//递归右子树:(前序起始位+左子树长度+1(根节点)),前序结束位不变,右子树为中序根节点+1,中序结束位保持不变
node.right=rebuild(pre,(i-instart+prestart)+1,preend,in,i+1,inend);
}
}
//当递归结束后,返回当前节点
return node;
}
public class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int x) { val = x; }
public String toString(){
return "节点:["+val+"] 左孩子:{"+left+"} 右孩子:{"+right+"}";
}
}
}