首先應該明確:(前序遍歷+中序遍歷)和(後序遍歷+中序遍歷)能唯一確定一棵二叉樹;而前序遍歷[根節點 左子樹 右子樹]和後序遍歷[左子樹 右子樹 根節點]不能唯一確定一顆二叉樹。
因為我們不能從這兩種遍歷中區分出左子樹和右子樹的區間。這裡有乙個例子
但是如果這棵樹是真二叉樹(所有節點的度要麼為0,要麼為2,即左兒子和右兒子同時存在),那麼(前序遍歷+後序遍歷)就能重構一棵二叉樹。如下圖所示:
分析一下:二叉樹前序遍歷的第乙個元素和後序遍歷的最後乙個元素為樹根,後序遍歷序列的倒數第二個元素為右子樹的根,前序遍歷中右子樹的根的前面的元素均為左子樹元素,從而分隔左右子樹的元素,因此可以採用遞迴依次構建每一棵子樹。
前序[1,2,4,5,3,6,7]
後序[4,5,2,6,7,3,1]
對於前序遍歷,1後面的2是左子樹的根節點;對於右子樹,1前面的3是右子樹的根節點。左子樹的根節點2,在後序遍歷中2之前的(包括2,都是左子樹的部分)。
下面給出重構一棵二叉樹的各種形式:
1、前序+中序
public hashmapmap; //2、中序+後序建立《節點值,陣列下標》的對映關係
/*重構一棵二叉樹:前序遍歷 + 中序遍歷
public treenode buildtree(int preorder, int inorder)
return mybuildtree(preorder, inorder, 0, len-1, 0, len-1);
}public treenode mybuildtree(int preorder, int inorder, int preorderleft, int preorderright, int inorderleft, int inorderright)
//確定根節點
int preorderroot = preorderleft;
treenode root = new treenode(preorder[preorderroot]);
int inorderroot = map.get(root.val);
int sizeoflefttree = inorderroot - inorderleft; // 左子樹的大小
//構建左子樹
root.left = mybuildtree(preorder, inorder, preorderleft+1, preorderleft+sizeoflefttree, inorderleft,inorderroot-1);
//構建右子樹
root.right = mybuildtree(preorder, inorder, preorderleft+sizeoflefttree+1, preorderright, inorderroot+1,inorderright);
return root;
}
public treenode buildtree(int inorder, int3、前序+後序postorder)
return mybuildtree(inorder, postorder, 0, len-1, 0, len-1);
}public treenode mybuildtree(int inorder, int postorder, int inorderleft, int inorderright, int postorderleft, int
postorderright)
//根節點
int postorderroot =postorderright;
treenode root = new
treenode(postorder[postorderroot]);
int inorderroot =map.get(root.val);
int sizeoflefttree = inorderroot -inorderleft;
//建立左子樹
root.left = mybuildtree(inorder, postorder, inorderleft, inorderroot-1, postorderleft, postorderleft + sizeoflefttree-1);
//建立右子樹
root.right = mybuildtree(inorder, postorder, inorderroot+1, inorderright, postorderleft+sizeoflefttree+1, postorderroot-1);
return
root;
}
private hashmapmap; //《值,下標》
public treenode buildtree(int preorder, int
postorder)
map = new hashmap<>();
int len =preorder.length;
for (int i = 0; i < len; i++)
return mybuildtree(preorder, postorder, 0, len-1, 0, len-1);
}public treenode mybuildtree(int preorder, int postorder, int preorderleft, int preorderright, int postorderleft, int
postorderright)
//注意這個特判條件,否則4會出現陣列越界
if (preorderleft == preorderright || postorderleft ==postorderright)
//根節點
int preorderroot =preorderleft;
treenode root = new
treenode(preorder[preorderleft]);
//前序遍歷的第二個節點就是左子樹的根節點
int preorderlefttreeroot = preorderleft + 1; //
3int postorderlefttreeroot = map.get(preorder[preorderlefttreeroot]); //
4
//確定左子樹的長度
int sizeoflefttree = postorderlefttreeroot - postorderleft + 1;
//確定右子樹的長度
int sizeofrighttree = postorderright - postorderlefttreeroot - 1;
//構建左子樹
root.left = mybuildtree(preorder, postorder, preorderlefttreeroot, preorderlefttreeroot+sizeoflefttree-1, postorderleft, postorderlefttreeroot);
//構建右子樹
root.right = mybuildtree(preorder, postorder, preorderlefttreeroot+sizeoflefttree, preorderright, postorderlefttreeroot+1, postorderlefttreeroot+sizeofrighttree);
return
root;
}
劍指offer07 重建二叉樹
這是乙個非常高頻的面試題。題目 輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例子 前序遍歷 preorder 3,9,20,15,7 中序遍歷 inorder 9,3,15,20,7 思路 題目給出了前序和中序遍歷,我們可以知道前序的...
劍指 Offer 07 重建二叉樹
難度 中等 題目描述 解題思路 這道題之前做過,但是忘得乾乾淨淨了。現在再做一遍撿一撿,說不定哪次面試就出到了呢 總體思想就是遞迴,用雜湊表來儲存對應的中序遍歷的下標,空間換時間,免得每次都要去遍歷找下標。然後每次遞迴的時候,要給對應的左子樹和右子樹在對應陣列裡的下標,左端點大於右端點的時候返回空。...
劍指 Offer 07 重建二叉樹
首先要懂得前序遍歷和中序遍歷,可以寫出兩個陣列,自己手動來重建一下二叉樹,來看看重建二叉樹是怎麼乙個流程。以圖中給出的二叉樹為例,根據前序遍歷的特點,可知前序遍歷的首尾數字是根節點,比如這個時候根節點數值為3,可以在中序遍歷中第2個位置找到數值3,在3左邊的9為3的左子樹,右邊的15,20,7為右子...