7.重建二叉樹
題目描述
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
思路
思路和書上的一樣。
複述一下
將問題分解爲每次確定父節點,和左右子樹集合的問題。
第一個父節點即是根節點。
前序遍歷:根 左 右
中序遍歷:左 根 右
因此,在前序遍歷輸出的結果中,第一個值是 root 節點。
而在中序遍歷中, root 節點的左邊都是左子樹的節點。 root 節點的右邊都是右子樹的節點。於是,根據中序遍歷,可以得到左子樹和右子樹的節點個數。有了左右子樹的節點個數,就可以在前序遍歷中,也劃分出左右子樹的位置。
將上面的話總結一下:
- 根據前序遍歷,獲得當前書的 父節點值;
- 根據父節點值,在中序遍歷中,獲得左右節點個數的值;
- 根據左右節點的個數,確定前序遍歷中,左右子樹的範圍;
用題目中的例子來說明思想:
已知:
前序: 1 2 4 7 3 5 6 8
中序: 4 7 2 1 5 3 8 6
第一步:
前序序列第一個值,是root = 1
第二步,找到中序序列中 值爲1的位置,獲得左右子樹:
(4 7 2) 1 (5 3 8 6)
可以看到,左子樹有3個節點。右子樹一共有 4 個節點。
第三步
於是,可以在前序序列中也進行劃分
1 (2 4 7) (3 5 6 8)
遞歸地,可知,根節點左子樹的父節點值是2. 右子樹的父節點值是3.
代碼
/**
* 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.empty() || vin.empty() || pre.size() != vin.size()) return NULL;
TreeNode* root = help(pre, vin, 0, pre.size()-1, 0, vin.size()-1);
return root;
}
//pl = pre left; pr = pre right
// vl = vin left; vr = vin right
TreeNode* help(vector<int> pre, vector<int> vin, int pl, int pr, int vl, int vr) {
TreeNode* node = new TreeNode(pre[pl]);
if (pl == pr) {
if (vl == vr && pre[pl] == vin[vl]) return node;
else {
cout<<"Error_01\n";
return NULL;
}
}
int middle = -1;
// 根據當前節點,找到左右子樹的集合
for (int i = vl; i <= vr; i++) {
if (node->val == vin[i]) {
middle = i;
break;
}
}
if (middle == -1) {
cout<<"Error_02\n";
return NULL;
}
node->left = help(pre, vin, pl+1, pl+middle-vl, vl, middle-1);
node->right = help(pre, vin,pl+middle-vl+1, pr, middle+1, vr);
return node;
}
};