演算法設計與分析課作業【week3】leetode--105. Construct Binary Tree from Preorder and Inorder Traversal
題目
Given preorder and inorder traversal of a tree, construct the binary tree.
Note: You may assume that duplicates do not exist in the tree.
For example, given
preorder = [3,9,20,15,7]
inorder = [9,3,15,20,7]
Return the following binary tree:
3
/ \
9 20
/ \
15 7
題目要求是利用二叉樹的先序和中序遍歷的陣列,來構建二叉樹。
如果不瞭解二叉樹的先序和中序遍歷的話,別人的部落格都有介紹可以先了解下。這裡我們直接以知道遍歷方法來講述。
樹的先序遍歷先輸出樹的根節點,再輸出左子節點,再輸出右子節點。
樹的中序遍歷則是先輸出左子節點,再輸出根節點,最後輸出右子節點。
我們先由例子來找規律,由先序遍歷的陣列開始一個一個來,首先是3,由於先序遍歷是先輸出根節點的,所以先序遍歷陣列的第一個元素便是這棵二叉樹的根節點,即根節點是3。
然後我們看到3在中序遍歷陣列的第2個元素的位置,我們知道樹的中序遍歷先輸出左子節點,再輸出根節點,通俗的說就是先左,再中,後右。那麼在3之前輸出的就屬於3的左子樹,在3後面則屬於3的右子樹。所以由中序遍歷陣列我們可以初步得到以下樹形:
3
/ \
(9)(15,20, 7)
此時我們看先序遍歷陣列的第二個元素,第二個元素是9,也就是說9是3的左子樹的根節點,此時3的左子樹也只有9。所以此時左邊結束。
3
/ \
9 (15,20,7)
接下來我們看先序遍歷陣列的第三個元素,是20,也就是說20是3的右子樹的根節點,那麼我們再看20在中序遍歷陣列的位置,此時我們需要確定是3的右子樹,所以只需要看3的右子樹部分的數字,也就是看15,20,7這3個數的相對位置,可以看到15在20前輸出(在20左邊),7在20之後(在20後邊),也就是說,15是以20為根節點的左子樹的部分,而7則是以20為根節點的右子樹的部分。
此時我們便已得出我們所需要的二叉樹了。
3
/ \
9 20
/ \
15 7
總結一下步驟就是:
- 從頭到尾依次拿出先序遍歷陣列的一個元素,設為A。
- 確定該元素A在中序遍歷陣列的位置。在中序遍歷陣列中,位於元素A的左邊的元素則在樹中屬於元素A的左子樹,位於元素A的右邊的元素則在樹中屬於元素A的左子樹。
- 重複1,2直至所有元素排列完成。
這種特性用遞迴的方式就能很好的實現,C++程式碼如下:
/**
* Definition for a binary tree node.
* struct TreeNode {
* int val;
* TreeNode *left;
* TreeNode *right;
* TreeNode(int x) : val(x), left(NULL), right(NULL) {}
* };
*/
class Solution {
public:
TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) {
/*利用map來儲存樹元素在中序遍歷陣列的位置,
這樣取位置的時候不用每次遍歷一下陣列來獲得*/
map<int, int> nodesIndex;
int index = 0;
for (int i = 0; i < inorder.size(); ++i) {
nodesIndex[inorder[i]] = i;
}
if (preorder.size() == 0) return NULL;
TreeNode* head = new TreeNode(preorder[0]);
if (nodesIndex[preorder[0]] > 0) {
helpToBuildTree(preorder, nodesIndex, head, true, ++index, 0,
nodesIndex[preorder[0]] - 1);
}
if (nodesIndex[preorder[0]] < preorder.size() - 1) {
helpToBuildTree(preorder, nodesIndex, head, false, ++index,
nodesIndex[preorder[0]] + 1, preorder.size() - 1);
}
return head;
}
void helpToBuildTree(vector<int>& preorder, map<int, int>& nodesIndex,
TreeNode* node, bool left, int& index, int front, int latter) {
TreeNode* tmp;
if (left) {
node->left = new TreeNode(preorder[index]);
tmp = node->left;
}
else {
node->right = new TreeNode(preorder[index]);
tmp = node->right;
}
int inorderIndex = nodesIndex[preorder[index]];
if (inorderIndex > front) {
helpToBuildTree(preorder, nodesIndex, tmp, true, ++index,
front, inorderIndex - 1);
}
if (inorderIndex < latter) {
helpToBuildTree(preorder, nodesIndex, tmp, false, ++index,
inorderIndex + 1, latter);
}
}
};