問題
已知二叉樹的兩種遍歷順序(先序,中序,後序),構造完整的二叉樹。三道題分別是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;
}