问题
已知二叉树的两种遍历顺序(先序,中序,后序),构造完整的二叉树。三道题分别是LeetCode 105,LeetCode 106,LeetCode 889。
分析
先看看三种遍历顺序有哪些特点:
先序遍历:[根节点,左子树,右子树],然后每个左子树或者右子树又可以递归的继续划分
中序遍历:[左子树,根节点,右子树],然后每个左子树或者右子树又可以递归的继续划分
后序遍历:[左子树,右子树,根节点],然后每个左子树或者右子树又可以递归的继续划分
那么问题就可以划分为先根据两种遍历顺序来确定根节点位置:
1、已知先序和中序,那么先序数组的第一个位置即是根节点,然后遍历中序数组,找到根节点在中序数组的位置,在此位置之前的部分是左子树,然后确定先序数组中左子树的范围;之后的部分是右子树,然后确定先序数组中左子树的范围。
2、递归。(已知后序和中序类似)
但是如果是已知先序和后序的话,就属于另外一种情况:
1、找到先序数组中左子树的第一个节点,然后找到该节点在后序遍历数组的位置,那么在该节点之前(包括该节点)的都是左子树,该节点之后到根节点都是右子树部分。
2、递归。
代码
105:
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder.length==0||inorder.length==0)
return null;
TreeNode root = new TreeNode(preorder[0]);
for(int i=0;i<inorder.length;i++){
if(preorder[0]==inorder[i]){
break;
}
root.left = buildTree(Arrays.copyOfRange(preorder,1,i+1),Arrays.copyOfRange(inorder,0,i));
root.right = buildTree(Arrays.copyOfRange(preorder,i+1,preorder.length),Arrays.copyOfRange(inorder,i+1,inorder.length));
}
return root;
}
106:
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(inorder.length==0||postorder.length==0){
return null;
}
TreeNode root = new TreeNode(postorder[postorder.length-1]);
for(int i=0;i<inorder.length;i++){
if(inorder[i]==postorder[postorder.length-1]){
break;
}
}
root.left = buildTree(Arrays.copyOfRange(inorder,0,i),Arrays.copyOfRange(postorder,0,i));
root.right = buildTree(Arrays.copyOfRange(inorder,i+1,inorder.length),Arrays.copyOfRange(postorder,i,postorder.length-1));
return root;
}
889
public TreeNode constructFromPrePost(int[] pre, int[] post) {
int N = pre.length;
if(N==0) return null;
TreeNode node = new TreeNode(pre[0]);
if(N==1) return node;
int i=0;
for(;i<pre.length;i++){
if(pre[1]==post[i]) {
break;
}
}
node.left = constructFromPrePost(Arrays.copyOfRange(pre, 1,i+2),Arrays.copyOfRange(post,0,i+1));
node.right = constructFromPrePost(Arrays.copyOfRange(pre,i+2,N),Arrays.copyOfRange(post,i+1,N-1));
return node;
}