---
# System prepended metadata

title: 演算法導論 HW7

---

# 演算法導論 HW7
https://hackmd.io/@wang1234/HJMuNhkm2
## 第1題: knapsack problem背包問題(Ch3)
n=4 , M=80 ,
(p₁ , p₂ , p₃ , p₄)=(100,60,30,60)
(w₁ , w₂ , w₃ , w₄)=(20,40,10,30)
p₁/w₁ = 100/20 = 5   ⇒ 1
p₂/w₂ = 60/40 = 1.5   ⇒ 0.5
p₃/w₃ = 30/10 = 3   ⇒ 1
p₄/w₄ = 60/30 = 2   ⇒ 1
20×1 + 10×1 + 30×1 + 40×0.5 = 80
<font color=#3535FF>x₁=1 , x₂=0.5 , x₃=1 , x₄=1</font>

## 第2題: Closest Pair Problem
![](https://i.imgur.com/l5Dlwah.png)
以分半的方式將集合S從x=L處分成的S<sub>L</sub>和S<sub>R</sub>，
然後分別計算出他們內部最近點的距離，令其為d<sub>L</sub>和d<sub>R</sub>，再取兩者的最小值設為d，
而後回到分界線x=L處，以位在x=L-d ~ L區塊的點的y值，例如:有一<font color=＃008000>P點座標(a,b)</font>，
對應到另半邊<font color=＃00A2FF>x=L ~ L+d</font>的區塊，在<font color=＃00A2FF>y=b-d ~ b+d</font>內尋找是否有落點，且實際計算其與P點的距離是否小於d;
若是位於x=L ~ L+d區塊的點，則在x=L-d ~ L區塊搜索
將此交界處檢查一遍後便可得到集合S裡最近點的距離

## 第3題: Convex Hull Problem
<font color="DarkGray" class="small">請說明Convex Hull Problem，
![](https://i.imgur.com/mM1fT0f.png)
(1)為何不直接用sort來得到polygon，而要採用merge?</font>
<b>sort做法: </b>從左側多邊形中心的一p點連線至左右兩多邊形的頂點，依連線的角度進行排序，得到合併後的多邊形
<b>merge做法: </b>在合併後的多邊形的有三項特性，
其一是p點所在的左側多邊形，全部頂點依然維持逆時針方向，
而右側部分則以縱向上的最低點與最高點分為兩半，右半部分也依然維持逆時針方向，
但位於(右側多邊形)左半部分的頂點要變成順時針方向的排序，
依這些特性整理出三個區塊，再進行merge
<font color=＃00A2FF>因為merge做法的時間複雜度比sort做法的低</font>
<font color="DarkGray" class="small">(2)請說明如何將polygon，修改成convex hull？</font>
<font color=＃00A2FF>將在合併後的多邊形裡，造成reflex angle(反角:內角角度為180°~360°)的節點刪除</font>

## 第4題: 將linked list的數列排序
[148. Sort List](https://leetcode.com/problems/sort-list/)
<font color="Black">解題思路:
> 主要解題的merge sort程式碼式來自其他網頁
> 有merge_sort和merge兩個函式
> 在merge_sort裡用遞迴的方式將list切分成兩半
> 直到傳入的list(nlst)只剩一個或零個成員(空列表)
> 在merge裡則將傳入的兩個list(left,right)比較大小並進行合併</font>
```python=
class Solution:
    def sortList(self, head: ListNode) -> ListNode:
        def merge(left, right):
            output = []
            while left and right:
                if left[0] <= right[0]:
                    output.append(left.pop(0))
                else:
                    output.append(right.pop(0))
            if left:
                output += left
            if right:
                output += right
            return output

        def merge_sort(nlst):
            if len(nlst) <= 1:
                return nlst
            mid = len(nlst) // 2
            left = nlst[:mid]
            right = nlst[mid:]
            left = merge_sort(left)
            right = merge_sort(right)
            return merge(left, right)
        
        temp=[]
        while head:
            temp.append(head.val)
            head=head.next
        temp=merge_sort(temp)
        p=ListNode(0)
        ans=p
        for i in temp:
            p.next=ListNode(i)
            p=p.next
        return ans.next
```
![](https://i.imgur.com/y27Tc6F.png)
花60分鐘，參考:
[Converting a list to a linked list](https://stackoverflow.com/questions/31553576/converting-a-list-to-a-linked-list)
[【Day25】[演算法]-合併排序法Merge Sort](https://ithelp.ithome.com.tw/articles/10278179)
[Python tutorial 20 | Merge Sort （合併排序法）](https://anchi-tang.medium.com/python-tutorial-20-merge-sort-%E5%90%88%E4%BD%B5%E6%8E%92%E5%BA%8F%E6%B3%95-dd3e087898a6)

## 第5題: 將排序好的數列轉為二元搜尋樹
[108. Convert Sorted Array to Binary Search Tree](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/description/)
<font color="Black">解題思路:
> 因為題目給的是遞增list,所以可以優先選擇位於列表中間的值來加入BST,做為root或parent
> 由此便能建構出平衡的BST
> 再用遞迴傳入比選到的節點(node)小的部分,以建構左子樹
> 比選到的節點大的部分,則建構右子樹</font>
```python=
class Solution:
    def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]:
        def bst(start,end):
            if start > end:
                return None
            mid=(start + end)//2
            root=TreeNode(nums[mid])
            root.left=bst(start,mid-1)
            root.right=bst(mid+1,end)
            return root
        return bst(0,len(nums)-1)
```
![](https://i.imgur.com/mq30ZkL.png)
花40分鐘，抄:
[資料結構 - Tree 的介紹(使用Python)](https://newaurora.pixnet.net/blog/post/224703989)
[Easy Python Solution](https://leetcode.com/problems/convert-sorted-array-to-binary-search-tree/solutions/2407334/easy-python-solution/?page=2&languageTags=python3)

## 第6題： 美麗數列
[932. Beautiful Array](https://leetcode.com/problems/beautiful-array/)
<font color="Black">解題思路:
> 我只有觀察出把奇數與偶數各分一邊,就能分成兩個互不影響的區塊
> 直到去觀摩的Solutions裡的程式碼,才發現只要延續從list分割奇偶數的規則繼續切割,最後再合併便可得到解答</font>
![](https://i.imgur.com/iT5xwNz.png)
```python=
class Solution:
    def beautifulArray(self, n: int) -> List[int]:
        nums = list(range(1, n+1))
        
        def helper(nums) -> List[int]:
            if len(nums) < 3:
                return nums
            odd = nums[::2]
            even = nums[1::2]
            return helper(odd) + helper(even)

        return helper(nums) 
```
![](https://i.imgur.com/nhFO0r4.png)
花90分鐘，抄:
[Python easy solution](https://leetcode.com/problems/beautiful-array/solutions/1676288/python-easy-solution/?languageTags=python3)
[Python3 solution with detailed explanation - Beautiful Array](https://leetcode.com/problems/beautiful-array/solutions/644612/python3-solution-with-detailed-explanation-beautiful-array/?languageTags=python3&topicTags=divide-and-conquer)

## 心得
這次的程式題都借助其他資訊或答案才完成，對merge sort、Linked List、Binary search tree，甚至包括遞迴，在觀念不清晰或應用不熟練，導致沒能夠自己寫出解法。