import java.util.HashMap;
import java.util.Map;
/**
* 题目:根据给定的先序和中序遍历数组构造一颗二叉树(无重复节点)
* 测试链接:https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal
*/
public class ConstructBinaryTree {
public static class TreeNode {
int val;
TreeNode left;
TreeNode right;
TreeNode(int val) {
this.val = val;
}
}
/**
* 构造二叉树,返回头节点
* @param pre 先序数组
* @param in 中序数组
* @return
*/
public static TreeNode buildTree(int[] pre,int[] in){
//边界条件
if (pre == null || in == null || pre.length != in.length){
return null;
}
// return f1(pre,0,pre.length-1,in,0,in.length-1);
//构建索引表
Map<Integer,Integer> indexMap = new HashMap<>();
for (int i=0;i<in.length;i++){
indexMap.put(in[i],i);
}
return f2(pre,0,pre.length-1,in,0,in.length-1,indexMap);
}
/**
* 递归函数
* @param pre
* @param L1
* @param R1
* @param in
* @param L2
* @param R2
* @return
*/
public static TreeNode f1(int[] pre,int L1,int R1,int[] in,int L2,int R2){
/*
比如先序是[1,2,3],中序也是[1,2,3],
那么这棵树没有左半边,递归调用head.left的时候
就会出现L1>R1的情况,直接返回null
*/
if (L1 > R1){
return null;
}
//先序的第一个节点必然是head节点
TreeNode head = new TreeNode(pre[L1]);
if (L1 == R1){
//只有一个直接返回即可
return head;
}
/*
在中序数组内找到head的位置,那么左边就是它的左子树,右边就是它的右子树
*/
int find = L2;
while (in[find] != pre[L1]){
find++;
}
head.left = f1(pre,L1+1,L1+find-L2,in,L2,find-1);
head.right = f1(pre,L1+find-L2+1,R1,in,find+1,R2);
return head;
}
/**
* 递归函数(优化版)
* @param pre
* @param L1
* @param R1
* @param in
* @param L2
* @param R2
* @param indexMap 中序数组每个数对应位置的索引表
* @return
*/
public static TreeNode f2(int[] pre, int L1, int R1, int[] in, int L2, int R2, Map<Integer,Integer> indexMap){
if (L1 > R1){
return null;
}
TreeNode head = new TreeNode(pre[L1]);
if (L1 == R1){
return head;
}
//此处替换为从索引表中获取位置
int find = indexMap.get(pre[L1]);
head.left = f2(pre,L1+1,L1+find-L2,in,L2,find-1,indexMap);
head.right = f2(pre,L1+find-L2+1,R1,in,find+1,R2,indexMap);
return head;
}
}