# **演算法作業 HW8** <font size=5>**1. Voronoi Diagram**</font> --- * 請畫出下圖兩個VD合併結果,畫出新建立的線段(註明為哪兩點的中垂線),並說明簡述流程。 ![](https://hackmd.io/_uploads/S1-25WNNh.png) ans:新建立線段(綠色)、輔助線(藍色、紅色) ![](https://hackmd.io/_uploads/rkbtqW4Vh.png) 首先將兩個VD的凸包合併,得到新的凸包。 接著從新得到的連線(b15 or b26)開始畫中垂線。 若線段跟其他中垂線交錯則轉折,置換成其他點的中垂線。 (基本上就是置換成兩條交錯中垂線中三個點的第三條中垂線) 畫完最後兩點,將超出的部分去除就完成了。 <font size=5>**2. Voronoi Diagram的應用**</font> --- * 請說明The Euclidean all nearest neighbor problem為何,以及如何應用VD來解此問題? ans: 找出距離給定點最近的點,利用VD圖劃分出的區域可以很輕鬆得到答案。 先將VD圖的每一點畫出互相平行的切線,得到許多平條區。 而每個平條區又被劃分成許多區域。 先找出點屬於哪一個平條,再找出屬於平條內哪個區域就解決了。 <font size=5>**3. FFT**</font> --- * 當輸入為:{1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16},請說明如何應用FFT得到結果(只須說明計算過程,不用算出結果)? ans: 利用分治法的思維,每次分成奇數項跟偶數項(重複利用算過的結果來節省計算)。 不斷分割到最小問題後再往回算出更大的問題,直到計算出最後的結果。 <font size=6>**程式題:Divide and Conquer**</font> --- <font size=5>**4. 由Preorder與Inorder建構二元樹**</font> --- [Construct Binary Tree from Preorder and Inorder Traversal - LeetCode](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/) 只要清楚前序跟中序的排列方式,就可以輕鬆的推導出答案了。 前序排列可以想成 **{ 父節點、{左子樹}、{右子樹} }**。 中序排列可以想成 **{ {左子樹}、父節點、{右子樹} }**。 構造時從前序中提出父節點,接著再呼叫左子樹右子樹的構造。 不斷重複上述步驟,直到構建完樹為止。 而子樹範圍可以從中序得出,藉此從前序中取出左子樹及右子樹呼叫。 完全靠自己,完成時間:十分鐘。 ```c++ /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: TreeNode* buildTree(vector<int>& preorder, vector<int>& inorder) { unordered_map<int,int> mp; for(int i=0;i<inorder.size();++i) mp[inorder[i]]=i;//用map紀錄元素在inorder內的索引 //用map去存的前提是元素不能重複 TreeNode* root = construct(preorder,0,preorder.size()-1,inorder,0,inorder.size()-1,mp); return root; } TreeNode* construct(vector<int>&preorder, int preStart, int preEnd, vector<int> &inorder,int inStart, int inEnd,unordered_map<int,int> &mp){ if(preStart>preEnd || inStart>inEnd) return NULL; TreeNode* root = new TreeNode(preorder[preStart]); int inRoot = mp[root->val]; int numsLeft = inRoot-inStart;//左子樹的點數量 root->left = construct(preorder,preStart+1,preStart+numsLeft,inorder,inStart,inRoot-1,mp); root->right = construct(preorder,preStart+numsLeft+1,preEnd,inorder,inRoot+1,inEnd,mp); return root; } }; ``` ![](https://hackmd.io/_uploads/H1EzCzEEh.png) <font size=5>**5. 由Postorder與Inorder建構二元樹**</font> --- [Construct Binary Tree from Inorder and Postorder Traversal - LeetCode](https://leetcode.com/problems/construct-binary-tree-from-inorder-and-postorder-traversal/) 跟上一題同樣道理,只要搞清楚後序跟中序的排列就沒什麼難的。 後序排列可以想成 **{{左子樹}、{右子樹},父節點 }**。 中序排列可以想成 **{ {左子樹}、父節點、{右子樹} }**。 構造時從後序中提出父節點,接著再呼叫左子樹右子樹的構造。 不斷重複上述步驟,直到構建完樹為止。 而子樹範圍可以從中序得出,藉此從後序中取出左子樹及右子樹呼叫。 完全靠自己,完成時間:五分鐘。 ```c++ /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: TreeNode* buildTree(vector<int>& inorder, vector<int>& postorder) { unordered_map<int,int> mp; for(int i=0;i<inorder.size();++i) mp[inorder[i]]=i;//用map紀錄元素在inorder內的索引 //用map去存的前提是元素不能重複 TreeNode* root = construct(postorder,0,postorder.size()-1,inorder,0,inorder.size()-1,mp); return root; } TreeNode* construct(vector<int>&postorder, int postStart, int postEnd, vector<int> &inorder,int inStart, int inEnd,unordered_map<int,int> &mp){ if(postStart>postEnd || inStart>inEnd) return NULL; TreeNode* root = new TreeNode(postorder[postEnd]); int inRoot = mp[root->val]; int numsRight = inEnd-inRoot;//右子樹的點數量 root->left = construct(postorder,postStart,postEnd-numsRight-1,inorder,inStart,inRoot-1,mp); root->right = construct(postorder,postEnd-numsRight,postEnd-1,inorder,inRoot+1,inEnd,mp); return root; } }; ``` ![](https://hackmd.io/_uploads/HkbrHXVN2.png) <font size=5>**6. 由Pretorder與Postorder建構二元樹**</font> --- [Construct Binary Tree from Preorder and Postorder Traversal - LeetCode](https://leetcode.com/problems/construct-binary-tree-from-preorder-and-postorder-traversal/) 前序和後序並不能保證一個二元樹的構造,但是不影響構建出一個二元樹。 步驟跟前面相同,透過前序跟後序的特性取得左右子樹的根節點。 呼叫遞迴將二元樹構造出來就行了。 要注意的是,這三題的值都不會重複,所以才用map方便查找。 如果有重複的值就不能這樣做。 完全靠自己,完成時間:五分鐘。 ```c++ /** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode() : val(0), left(nullptr), right(nullptr) {} * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} * }; */ class Solution { public: TreeNode* constructFromPrePost(vector<int>& preorder, vector<int>& postorder) { unordered_map<int,int> mp; for(int i=0;i<postorder.size();++i) mp[postorder[i]]=i;//用map紀錄元素在postorder內的索引 //用map去存的前提是元素不能重複 TreeNode* root = construct(preorder,0,preorder.size()-1,postorder,0,postorder.size()-1,mp); return root; } TreeNode* construct(vector<int>&preorder, int preStart, int preEnd, vector<int>&postorder,int postStart, int postEnd,unordered_map<int,int> &mp){ if(preStart>preEnd || postStart>postEnd) return NULL; TreeNode* root = new TreeNode(preorder[preStart]); if(preStart == preEnd) return root;//剩一個節點時直接回傳,不然下面會出錯 int Lv = preorder[preStart+1];//左子樹根節點的值 int postLeftRoot = mp[Lv];//左子樹根節點在後序中索引 int numsLeft = postLeftRoot-postStart+1;//左子樹的點數量 root->left = construct(preorder,preStart+1,preStart+numsLeft,postorder,postStart,postLeftRoot,mp); root->right = construct(preorder,preStart+numsLeft+1,preEnd,postorder,postLeftRoot+1,postEnd-1,mp); return root; } }; ``` ![](https://hackmd.io/_uploads/ry41lHE42.png) <font size=5>**7. 本周心得**</font> --- 這周的題目之前做過了,只要搞懂特性就沒什麼困難的,很好理解。 --- 若有錯誤歡迎指正