解题思路:
依次取出先序遍历的每个节点,取出的第一个结点 A,一定是根节点;
再取出第二个节点 B,此时不能确定 B 是 A 的左子树还是右子树,需要看中序遍历;
在中序遍历中,如果 B 在 A 的左侧,那么 B 就是 A 的左子树,如果 B 在 A 的右侧,那么 B 就是 A 的右子树;
以此类推
// 成员变量,index 表示当前访问到 先序 中的第几个元素
public int index = 0;
public TreeNode buildTree(int[] preorder, int[] inorder) {
// 由于输入的用例可能有多组,所以在方法入口这里把 index 还原成 0,防止多个用例之间干扰
index = 0;
// 辅助递归方法中后两个参数表示当前这个子树对应的中序遍历结果
// 使用这一对下标表示当前子树的中序遍历结果是在 inorder 的那个部分上
return _buildTree(preorder, inorder,0,inorder.length);
}
// [inorderLeft, inorderRight) 标注了一个前闭后开的区间
// inorder 数组上的这个区间中的内容, 就正是当前子树的中序遍历结果
public TreeNode _buildTree(int[] preorder, int[] inorder,
int inorderLeft, int inorderRight) {
if(inorderLeft>inorderRight){
//中序区间是一个空区间,说明当前子树是空树
return null;
}
if (index >= preorder.length) {
//先序结果遍历完毕,整个树就处理完了
return null;
}
//处理一般情况,仍然是进行先序遍历
//访问结点操作不是打印,而是构建结点
TreeNode root = new TreeNode(preorder[index]);
//查找当前结点在中序区间中所处的位置
int pos = find(inorder,inorderLeft,inorderRight,root.val);
//有了 pos 之后,就知道了当前结点左右子树的中序区间
//左子树的中序区间:[inorderLeft,pos)
//右子树的中序区间:(pos+1,inorderRight]
//递归处理左右子树
//此处 index 只 ++ 一次
//如果遍历结果中有空节点,就要 ++ 两次
//如果没有空节点,只 ++ 一次
index++;
root.left = _buildTree(preorder, inorder, inorderLeft, pos);
root.right = _buildTree(preorder, inorder, pos+1, inorderRight);
return root;
}
private int find(int[] array, int left, int right, int toFind) {
for(int i=left;i<right;i++){
if(array[i]==toFind){
return i;
}
}
return -1;
}