---
# System prepended metadata

title: '**演算法作業 HW8**'

---

# **演算法作業 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>
---
這周的題目之前做過了，只要搞懂特性就沒什麼困難的，很好理解。

---
若有錯誤歡迎指正
