# 演算法作業 HW8 # 觀念題 ## 第1題: Voronoi Diagram ![](https://i.imgur.com/31fwEku.png) ![](https://i.imgur.com/WhYGRex.png) ![](https://i.imgur.com/htwgo2B.png) ## 第2題: Voronoi Diagram的應用 ![](https://i.imgur.com/GEisH5m.png) ## 第3題: FFT ![](https://i.imgur.com/ES8IZBJ.png) # 程式題 ## 第4題: 由Preorder與Inorder建構二元樹 ### 通過畫面截圖 ![](https://i.imgur.com/HxX9hiw.png) ### 程式碼 ```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) { // 建立一個哈希表,用來存儲中序遍歷序列中每個節點對應的索引 unordered_map<int, int> inorder_map; for (int i = 0; i < inorder.size(); i++) { inorder_map[inorder[i]] = i; } // 調用遞歸函數構建二叉樹 return buildTreeHelper(preorder, 0, preorder.size()-1, inorder, 0, inorder.size()-1, inorder_map); } // 遞歸構建二叉樹 TreeNode* buildTreeHelper(vector<int>& preorder, int pre_start, int pre_end, vector<int>& inorder, int in_start, int in_end, unordered_map<int, int>& inorder_map) { // 如果前序遍歷序列中的左指針大於右指針,則返回空指針 if (pre_start > pre_end) { return nullptr; } // 建立一個新節點作為樹的根節點 TreeNode* root = new TreeNode(preorder[pre_start]); // 在中序遍歷序列中找到樹的根節點的索引 int root_index = inorder_map[root->val]; // 左子樹的節點個數 int left_tree_size = root_index - in_start; // 遞歸構建左子樹和右子樹 root->left = buildTreeHelper(preorder, pre_start+1, pre_start+left_tree_size, inorder, in_start, root_index-1, inorder_map); root->right = buildTreeHelper(preorder, pre_start+left_tree_size+1, pre_end, inorder, root_index+1, in_end, inorder_map); return root; } }; ``` ### 解題思路 先建立一個哈希表來儲存inorder中每個節點值對應的索引,然後用一個輔助函數來做BST。 在輔助函數中,先判斷遞歸終止條件。 如果pre_start大於pre_end,則返回空指針。 否則用Preorder去構建根節點。 然後在inorder中查找根節點的位置,並計算左子樹的節點數。 最後,我們遞歸構建left tree和right tree, 並將它們分別作為當前節點的左子節點和右子節點。 最後返回根節點。 ### 花費時間 半小時 ### 自己完成的比例 參考網路上的答案,尚未理解明白 ## 第5題: 由Postorder與Inorder建構二元樹 ### 通過畫面截圖 ![](https://i.imgur.com/zxQd65Y.png) ### 程式碼 ```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>& inorder, vector<int>& postorder) { unordered_map<int, int> inorder_map; for (int i = 0; i < inorder.size(); i++) { inorder_map[inorder[i]] = i; } return buildTreeHelper(inorder, 0, inorder.size()-1, postorder, 0, postorder.size()-1, inorder_map); } TreeNode* buildTreeHelper(vector<int>& inorder, int in_start, int in_end, vector<int>& postorder, int post_start, int post_end, unordered_map<int, int>& inorder_map) { if (in_start > in_end) { return nullptr; } TreeNode* root = new TreeNode(postorder[post_end]); int root_index = inorder_map[root->val]; int left_tree_size = root_index - in_start; root->left = buildTreeHelper(inorder, in_start, root_index-1, postorder, post_start, post_start+left_tree_size-1, inorder_map); root->right = buildTreeHelper(inorder, root_index+1, in_end, postorder, post_start+left_tree_size, post_end-1, inorder_map); return root; } }; ``` ### 解題思路 和前一個做法相似,先建立一個哈希表來儲存inorder中每個節點值對應的索引。 然後用一個輔助函數來進行BST。 在輔助函數中先判斷遞歸終止條件。 如果in_start大於in_end,則返回空指針。 否則,我們根據postorder結果構建根節點。 然後在中序遍歷中查找根節點的位置,並計算left tree的節點數。 最後,我們遞歸構建left tree和right tree, 並將它們分別作為當前節點的左子節點和右子節點。最後返回根節點即可。 ### 花費時間 二十分鐘 ### 自己完成的比例 參考網路上的答案,尚未理解明白 ## 第6題:由Pretorder與Postorder建構二元樹 ### 通過畫面截圖 ![](https://i.imgur.com/9lXvFEI.png) ### 程式碼 ```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* constructFromPrePost(vector<int>& pre, vector<int>& post) { return buildTreeHelper(pre, 0, pre.size()-1, post, 0, post.size()-1); } TreeNode* buildTreeHelper(vector<int>& pre, int pre_start, int pre_end, vector<int>& post, int post_start, int post_end) { if (pre_start > pre_end) { return nullptr; } TreeNode* root = new TreeNode(pre[pre_start]); if (pre_start == pre_end) { return root; } int left_root_val = pre[pre_start+1]; int left_root_index = -1; for (int i = post_start; i <= post_end; i++) { if (post[i] == left_root_val) { left_root_index = i; break; } } int left_tree_size = left_root_index - post_start + 1; root->left = buildTreeHelper(pre, pre_start+1, pre_start+left_tree_size, post, post_start, left_root_index); root->right = buildTreeHelper(pre, pre_start+left_tree_size+1, pre_end, post, left_root_index+1, post_end-1); return root; } }; ``` ### 解題思路 先根據preorder結果構建根節點。然後在postorder中查找左子樹的根節點。根據preorder中根節點後面的節點可以得到left tree的節點數量。最後,我們遞歸構建left tree和right tree,並將它們分別作為當前節點的左子節點和右子節點。最後返回根節點。 ### 花費時間 約一小時 ### 自己完成的比例 參考網路上的答案,尚未理解明白 ## 心得 這次的影片長度真的很長,而且是本學期以來最難的一次,稍加難懂,但是回放一兩次之後都會懂,然而第一題的解題,我覺得題目給的點有不夠精確的問題,導致我在畫圖的時候花了約半小時。程式題的部分,幸好與這次的觀念題沒有相關,解題解得比較快,若是程式題也與觀念題一樣難,我覺得恐怕以我的能力很難解出來。