leetcode-889-105-106-根據前-中-後遍歷構造二叉樹
目錄
- Posted by 微博@Yangsc_o
- 原創文章,版權宣告:自由轉載-非商用-非衍生-保持署名 | Creative Commons BY-NC-ND 3.0
本題是leetcode,地址
題目
889. 根據前序和後序遍歷構造二叉樹
返回與給定的前序和後序遍歷匹配的任何二叉樹。
pre 和 post 遍歷中的值是不同的正整數。
示例:
輸入:pre = [1,2,4,5,3,6,7], post = [4,5,2,6,7,3,1]
輸出:[1,2,3,4,5,6,7]提示:
1 <= pre.length == post.length <= 30
pre[] 和 post[] 都是 1, 2, ..., pre.length 的排列
每個輸入保證至少有一個答案。如果有多個答案,可以返回其中一個。根據一棵樹的前序遍歷與中序遍歷構造二叉樹。
注意:
你可以假設樹中沒有重複的元素。例如,給出
105. 從前序與中序遍歷序列構造二叉樹
前序遍歷 preorder = [3,9,20,15,7]
中序遍歷 inorder = [9,3,15,20,7]
返回如下的二叉樹:
3
/
9 20
/
15 7106. 從中序與後序遍歷序列構造二叉樹
根據一棵樹的中序遍歷與後序遍歷構造二叉樹。
注意:
你可以假設樹中沒有重複的元素。例如,給出
中序遍歷 inorder = [9,3,15,20,7]
後序遍歷 postorder = [9,15,7,20,3]
返回如下的二叉樹:
3
/
9 20
/
15 7
分析
其實這三道題非常類似,做題的前提是需要了解樹的前序遍歷、中序遍歷、後續遍歷的特點;
- 前序遍歷:遍歷順序,根-左-右;第一個節點就是根節點;
- 中序遍歷:遍歷順序,左-根-右;根節點是區分左右子樹的節點;
- 後續遍歷:遍歷順序,左-右-根;由此可知,根節點在最後;
[889. 根據前序和後序遍歷構造二叉樹]:
根據前序遍歷和後序遍歷特點,我們找到前序遍歷中的第一個非根節點在第二個節點的位置,就可以分別分離出:前序遍歷:(根)(左子樹)(右子樹)和 (左子樹)(右子樹)(根),這樣我們便得到一個根節點,分別對左子樹和右子樹進行遞迴操作,也可以分別獲取到其根節點,如此便可得到一顆完整的樹;
同理我們可以分析出 前+中;中+後的推斷邏輯;
一位網友概括如下:
前+後
首先我們可以顯然知道當前根節點為pre[pre_start],並且它在後序中的位置為post_end,因此這裡我們需要找到能區分左右子樹的節點。
我們知道左子樹的根節點為pre[pre_start+1],因此只要找到它在後序中的位置就可以分開左右子樹(index的含義)
前+中
首先我們可以顯然知道當前根節點為pre[pre_start],只用找出它在中序中的位置,就可以把左右子樹分開(index的含義)
中+後
首先我們可以顯然知道當前根節點為post[post_end],只用找出它在中序中的位置,就可以把左右子樹分開(index的含義)
code
// 889. 根據前序和後序遍歷構造二叉樹
public TreeNode constructFromPrePost(int[] pre, int[] post) {
if(pre==null || pre.length==0) {
return null;
}
TreeNode root = new TreeNode(pre[0]);
int length = pre.length;
if(length == 1) {
return root;
}
for(int index =0; index < length; index ++) {
if(pre[1] == post[index]) {
int[] pre_left = Arrays.copyOfRange(pre,1,index + 1 + 1);
int[] pre_right = Arrays.copyOfRange(pre,index + 1 + 1 ,length);
int[] post_left = Arrays.copyOfRange(post,0,index);
int[] post_right = Arrays.copyOfRange(post,index + 1, length -1);
root.left = constructFromPrePost(pre_left,post_left);
root.right = constructFromPrePost(pre_right,post_right);
break;
}
}
return root;
}
// 105. 從前序與中序遍歷序列構造二叉樹
public TreeNode buildTree(int[] preorder, int[] inorder) {
if(preorder == null || preorder.length == 0) {
return null;
}
int length = preorder.length;
TreeNode root = new TreeNode(preorder[0]);
if(length == 1) {
return root;
}
for(int index = 0; index < length; index ++) {
if(root.val == inorder[index]) {
int[] preorder_left = Arrays.copyOfRange(preorder,1,index + 1);
int[] preorder_right = Arrays.copyOfRange(preorder,index + 1, length);
int[] inorder_left = Arrays.copyOfRange(inorder,0,index);
int[] inorder_right = Arrays.copyOfRange(inorder,index + 1,length);
root.left = buildTree(preorder_left,inorder_left);
root.right = buildTree(preorder_right,inorder_right);
break;
}
}
return root;
}
// 106. 從中序與後序遍歷序列構造二叉樹
public TreeNode buildTree(int[] inorder, int[] postorder) {
if(postorder == null || postorder.length == 0) {
return null;
}
int length = postorder.length;
if(length == 1){
return new TreeNode(postorder[length -1]);
}
TreeNode root = new TreeNode(postorder[length - 1]);
for(int index = 0; index < length; index ++) {
if(postorder[length -1] == inorder[index]) {
int[] inorder_left = Arrays.copyOfRange(inorder,0,index);
int[] inorder_right = Arrays.copyOfRange(inorder,index + 1,length);
int[] postorder_left = Arrays.copyOfRange(postorder,0,index);
int[] postorder_right = Arrays.copyOfRange(postorder,index,length -1);
root.left = buildTree(inorder_left,postorder_left);
root.right = buildTree(inorder_right,postorder_right );
break;
}
}
return root;
}