# 演算法導論 HW1 https://hackmd.io/@wang1234/Bkc-g3nyc ## 1. 本週影片中提到的NP-complete問題有哪些? 給定一些數字,將這些數字分成兩個集合,使得兩集合內數字的總和相等(當數字少時能以列舉配隊的方式去解決,但數字多時此方法便非常費時) *NP-complete:當問題的規模變大時,演算法學者們找不到有效率的解法,(須經過嚴謹的演算法證明)* ## 2. 請上網找一個老師沒說過的NP-complete問題,並舉個例子說明該問題的輸入與輸出。 Vertex Cover Problem(頂點覆蓋問題):給定一個無向圖,頂點覆蓋問題是要找到最小頂點覆蓋(即用最少的頂點來覆蓋所有的邊) ![](https://i.imgur.com/bNIAQyc.png) 輸入:undirected tree(無向樹)(是一種無向圖),頂點集合V={A,B,C,D,E,F,G},邊集合E={(A,B),(A,E),(B,C),(D,E),(E,F),(F,G)} 輸出:{B,E,G} *參考資料來源:* * https://www.chegg.com/homework-help/questions-and-answers/vertex-cover-graph-g-v-e-subset-vertices-s-cv-includes-least-one-endpoint-every-edge-e-giv-q51659546 * https://www.geeksforgeeks.org/introduction-and-approximate-solution-for-vertex-cover-problem/ * https://zh.wikipedia.org/zh-tw/%E8%A6%86%E7%9B%96_(%E5%9B%BE%E8%AE%BA) ## 3. 二元搜尋應用:當數字可以重覆 解題思路: 原程式裡一旦在list中找到key,就可直接輸出其index,但若是數字可以重覆,就要先將找到的index儲存至變數temp,然後繼續針對index比temp小的區塊繼續搜尋,讓temp去存更小的index,最後如果temp不等於初始值(即曾在list中找到key且更動了temp),返回temp;否則,返回-1 ```python= def binary_search(data, key): temp = len(data) left, right = 0, len(data) - 1 while left <= right: mid = (left + right) // 2 if data[mid] < key: left = mid + 1 elif data[mid] > key: right = mid - 1 else: if mid < temp: temp = mid right = mid - 1 if temp != len(data): return temp else: return -1 data = [1, 3, 3, 6] key = 3 print(binary_search(data, key)) ``` ![](https://i.imgur.com/J4M5Lvq.png) 花30分鐘,完全靠自己 ## 4. 二元搜尋應用:找數字該插入的位置 解題思路: 需修改的部分在當list中找不到target時的處理,while迴圈結束後所儲存的mid對應list的index位置,其值若小於target,表示target應在其後方(mid+1)的位置插入;其值若大於target,那mid便是target該插入的位置 ```python= class Solution(object): def searchInsert(self, nums, target): left, right = 0, len(nums) - 1 while left <= right: mid = (left + right) // 2 if nums[mid] < target: left = mid + 1 elif nums[mid] > target: right = mid - 1 else: return mid if nums[mid] < target: return mid+1 else: return mid ``` ![](https://i.imgur.com/6dDPG9e.png) 花10分鐘,完全靠自己 ## 5. 二元搜尋應用:找到最早出問題的版本 解題思路: 有1到n個版本,所以將1和n分別設為list的邊界,若從這些版本是否有出錯的情況來看此list為[False,False,...,False,True,True,...,True],而要尋找的目標即是丟入isBadVersion()後第一個(號碼最小的)返還True的版本,由此可見,當isBadVersion(mid)返還True,應將搜尋上限拉至mid的前一位(mid-1);反之,返還False時,將搜尋下限拉至mid的後一位(mid+1),但最終mid存的數值可能是最後一個False或者第一個True的版本,因此輸出前還需要一次判斷,如果是False,那就要輸出下一個,才能符合題所求 ```python= class Solution(object): def firstBadVersion(self, n): left,right = 1, n while left <= right: mid = (left + right)//2 if isBadVersion(mid): right = mid -1 else: left = mid + 1 if isBadVersion(mid): return mid else: return mid+1 ``` ![](https://i.imgur.com/1WcdEL7.png) 花20分鐘,完全靠自己 ## 6. 二元搜尋應用:開根號後的整數部分 解題思路: 1. 利用對於所有大於等於0的整數x,√x<=x/2+1,由此,將搜索範圍設成0到int(1/2)+1 ![](https://i.imgur.com/i4QekyO.png) ![](https://i.imgur.com/9lhTZwW.png) |![](https://i.imgur.com/GiG941w.png)|![](https://i.imgur.com/Dwjz8PL.png)| *如果只把範圍設到int(1/2),當x=1時會出錯* 2. 當x是完全平方數,便會在跑while迴圈時返還其平方根;但如果不是,就需要再次做比較來判斷,在mid的平方小於x時,返還mid;在mid的平方大於x時,返還mid-1 ```python= class Solution(object): def mySqrt(self, x): left,right = 0, int(x/2)+1 while left <= right: mid = (left + right)//2 if mid*mid < x: left = mid + 1 elif mid*mid > x: right = mid -1 else: return mid if mid*mid < x: return mid else: return mid-1 ``` ![](https://i.imgur.com/sujX06Q.png) 花30分鐘,完全靠自己(後續發現有問題時,借助網路上的工具驗證) ## 7. 本週心得 前2題反覆看了幾次影片,卻還是覺得自己寫出的內容不夠清晰、完整,程式題的部分可能因為相互有關連,除了在第3題花了較久的時間理解二元搜尋的程式,其餘4~6題修改程式時還算快速、直覺,但是寫解題思路相當費時