題目:重建二叉樹
題目描述:
輸入某二叉樹的前序遍歷和中序遍歷的結(jié)果,請重建出該二叉樹。假設(shè)輸入的前序遍歷和中序遍歷的結(jié)果中都不含重復的數(shù)字馆里。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6}染坯,則重建二叉樹并返回。
題目知識:
首先看題目應該最先看到的是這個幾個關(guān)鍵點:1揽碘、二叉樹,2园匹、二叉樹的前中后三種遍歷雳刺。
先序遍歷:遍歷規(guī)則 根-左-右
中序遍歷:遍歷規(guī)則 左-根-右
后序遍歷:遍歷規(guī)則 左-右-根
接下來的排序:
先序遍歷:ABCDEFGHK
中序遍歷:BDCAEHGKF
后序遍歷:DCBHKGFEA
先說中序遍歷,先序遍歷的規(guī)則是
左根右
此時A是根節(jié)點裸违,遍歷A的左子樹掖桦;
A的左子樹存在,找到B供汛,此時B看做根節(jié)點枪汪,遍歷B的左子樹;
B的左子樹不存在怔昨,返回B雀久,根據(jù)【左根右】的遍歷規(guī)則,記錄B趁舀,遍歷B的右子樹赖捌;
B的右子樹存在,找到C赫编,此時C看做根節(jié)點巡蘸,遍歷C的左子樹;
C的左子樹存在擂送,找到D悦荒,由于D是葉子節(jié)點,無左子樹嘹吨,記錄D搬味,無右子樹,返回C蟀拷,根據(jù)【左根右】的遍歷規(guī)則碰纬,記錄C,遍歷C的右子樹问芬;
C的右子樹不存在悦析,返回B,B的右子樹遍歷完此衅,返回A强戴;
至此亭螟,A的左子樹遍歷完畢,根據(jù)【左根右】的遍歷規(guī)則骑歹,記錄A预烙,遍歷A的右子樹;
A的右子樹存在道媚,找到E扁掸,此時E看做根節(jié)點,遍歷E的左子樹最域;
E的左子樹不存在谴分,返回E,根據(jù)【左根右】的遍歷規(guī)則羡宙,記錄E狸剃,遍歷E的右子樹;
E的右子樹存在狗热,找到F,此時F看做根節(jié)點虑省,遍歷F的左子樹匿刮;
F的左子樹存在,找到G探颈,此時G看做根節(jié)點熟丸,遍歷G的左子樹;
G的左子樹存在伪节,找到H光羞,由于H是葉子節(jié)點,無左子樹怀大,記錄H纱兑,無右子樹,返回G化借,根據(jù)【左根右】的遍歷規(guī)則潜慎,記錄G,遍歷G的右子樹蓖康;
G的右子樹存在铐炫,找到K,由于K是葉子節(jié)點蒜焊,無左子樹倒信,記錄K,無右子樹泳梆,返回G鳖悠,根據(jù)【左根右】的遍歷規(guī)則榜掌,記錄F,遍歷F的右子樹竞穷;
F的右子樹不存在唐责,返回F,E的右子樹遍歷完畢瘾带,返回A鼠哥;
至此,A的右子樹也遍歷完畢看政;
那么接下來的前序和后序遍歷類似的方式遍歷朴恳。
題目分析
已知當知道先序
和中序
遍歷的序列,或者知道中序
和后序
遍歷序列時我們可以唯一確定一個二叉樹允蚣,當只知道先序
和后序
的時候我們不能確定唯一的一棵樹于颖。
那我們先聯(lián)系這樣一個題目:
已知先序序列:ABCDEFGH,中序序列:BDCEAFHG,求出最終的序列來。
首先嚷兔,先序和中序的遍歷規(guī)則分別是根左右
和左根右
,那么我們可以知道此序列的根節(jié)點是A森渐,在中序序列中,BDCE是A的左子樹冒晰,F(xiàn)HG是A的右子樹同衣。
于是先序遍歷也就分成這樣的
而B又在先序遍歷中是A左子樹的根節(jié)點,再回到中序遍歷中B是A座子樹的根節(jié)點壶运,那么DCE就是B的右子樹耐齐,那么此時的圖就變成了
那么我們接下來在看CDE,看先序遍歷知道C是CDE的根節(jié)點蒋情,再根據(jù)中序遍歷DCE知道D是C的左葉子節(jié)點埠况,E是C的有葉子節(jié)點,那么此時我們的整個左子樹完成了棵癣。
我們同樣對右子樹進行操作辕翰,在先序中右子樹的順序是:FGH,那么此右子樹的根節(jié)點是F浙巫,再看中序的順序是:FHG金蜀,F(xiàn)是根節(jié)點,那HG是F的右子樹
再看先序遍歷發(fā)現(xiàn)接下來的根節(jié)點是G的畴,那么F的右子樹節(jié)點是G渊抄,再看中序遍歷的結(jié)果HG,H是G的左子樹丧裁。
接下來
我們知道中序遍歷:CEDFBAHG护桦,后序遍歷:EFDCBHGA
我們知道:
1、根據(jù)后序遍歷知道此二叉樹的根節(jié)點是A煎娇,那么在中序遍歷中我們就可以分成左子樹:CEDFB二庵,右子樹HG贪染。
2、先看左子樹的后序:EFDCB催享,我們知道左子樹的根節(jié)點是B杭隙,再到中序CEDFB中我們知道。CEDF是B的左子樹因妙。
3痰憎、后序:EFDC,知道B的左子樹的根節(jié)點是C攀涵,铣耘,而在中序CEDF中我們知道EDF是C的右子樹
4、后序:EFD以故,知道C的右子樹的根節(jié)點是D蜗细,而在中序EDF中我們知道E和F分別是D的左葉子節(jié)點和有葉子結(jié)點
5、中序:HG怒详,我們知道是A的右子樹炉媒,后序中HGA,說明A的右子樹的根節(jié)點是G昆烁。
6橱野、中序遍歷中是HG,說明H是G的左葉子節(jié)點
綜上所述善玫,我們可以知道從遍歷中獲取整個二叉樹的方法
題目代碼:
/**
* Definition for binary tree
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* reConstructBinaryTree(vector<int> pre,vector<int> vin) {
if(pre.size() != vin.size()||pre.size() == 0 || vin.size() == 0) return NULL;
else{
TreeNode* resNode = createTreeNodeHelper(pre,vin,0,0,vin.size()-1);
return resNode;
}
}
TreeNode* createTreeNodeHelper(vector<int> pre, vector<int> vin,int preRootPos,int vinLeft,int vinRight){
// pre 前序 vin 中序 preRootPos 前序根節(jié)點位置 vinLeft 中序左邊界 vinRight 中序右邊界
int vinRootPos,rootVal;
rootVal = pre[preRootPos];//前序遍歷中根節(jié)點位置的值
if(vinLeft>vinRight) return NULL;
for(int i = vinLeft; i<=vinRight;i++){
if(vin[i] == rootVal)
vinRootPos = i; //根據(jù)根節(jié)點找到中序中根節(jié)點的位置vinRootPos,
}
int leftLen = vinRootPos - vinLeft;
TreeNode* resRoot = new TreeNode(rootVal);
resRoot->left = createTreeNodeHelper(pre,vin,preRootPos+1,vinLeft,vinRootPos-1);
resRoot->right = createTreeNodeHelper(pre,vin,preRootPos+leftLen+1,vinRootPos + 1, vinRight);
return resRoot;
}
};
通過迭代的方式,不斷查找密强。