描述
基于给出的前序遍历和中序遍历,构造出二叉树。
参考文献
Construct Binary Tree From Inorder and Preorder/Postorder Traversal
前序遍历和中序遍历的分析
重复值
在前序遍历和中序遍历中不会存在重复的item,因为如果存在重复的值,那么其表达的二叉树一定会产生歧义。
例如:
preorder = {8, 8}
inorder = {8, 8}
它的二叉树可以表述如下:
8 8
/ 或者 \
8 8
这两种形式都是合法的,所以在前序遍历和中序遍历中不会存在重复的item(当然还包括后序遍历啦)
解决办法
例如:
preorder = {7,10,4,3,1,2,8,11}
inorder = {4,10,3,1,7,11,8,2}
其二叉树为:
_______7______
/ \
__10__ ___2
/ \ /
4 3 _8
\ /
1 11
我们可以看出:
- 前序遍历中的第一个元素总会是有一个子树的root(例如:7)
- 而在中序遍历中该root(例如:7)总会把左子树和右子树分开
结合这两点,我们可以很清楚的发现,这是一个递归的过程:
1. 首先取出preorder的第一个元素,构造为root(例如:7)
2. 在inorder中寻找root(例如:7)的index位置,则在index之前的元素表示是该二叉树的左子树(例如:{4, 10, 3, 1}),index之前的元素是该二叉树的右子树(例如: {11, 8, 2})
3. 把第2步找到的左子树和右子树分别在preorder中去对应,这样就形成了preorder1和preorder2,再把这两个子树分别从第1步开始循环递归。
具体代码如下:
class Solution {
public TreeNode buildTree(int[] preorder, int[] inorder) {
return buildTree2(0, 0,inorder.length-1,inorder,preorder);
}
public TreeNode buildTree2(int inorder_head, int preorder_head,int inorder_tail,int[] inorder,int[] preorder) {
if(inorder_tail-inorder_head<0 || preorder_head>preorder.length-1)
return null;
TreeNode root= new TreeNode(preorder[preorder_head]);
int index = 0; // Index of current root in inorder
for (int i = inorder_head; i <= inorder_tail; i++) {
if (inorder[i] == root.val) {
index = i;
}
}
root.left=buildTree2(inorder_head,preorder_head+1,index-1,inorder,preorder);
root.right=buildTree2(index+1,preorder_head+index-inorder_head+1,inorder_tail,inorder,preorder);
return root;
}
}
代码分析
- 在每一次递归中要去inorder中寻找root,然后把它分为左右子树。
- inorder_head表示目前子树的头索引,inorder_tail表示目前子树的尾索引
- preorder_head指向的是当前root