# 演算法 二元搜尋法(續) ## :book: 第1題: ![](https://i.imgur.com/VqXrh68.png) 複雜度=$O( n$^3^$)$ $c=4$ $3n$^3^$-5n+6<=4n$^3^ $n$^3^$>=-5n+6$ $n$^3^$+5n>=6$ $n(n$^2^$+5)>=6$ $n$^2^$+5>=6$ or $n>=6$ $n>=1$ | $n$ | $f(n)=3n$^3^$-5n+6$ | $cg(n)=4n$^3^ | | -------- | -------- | -------- | | 1 | 4 | 4 | | 2 | 20 | 32 | | 3 | 72 | 108 | $c=4$ $n_0$$=1$ --- ## :book: 第2題: ![](https://i.imgur.com/x1rxQtr.png) 複雜度=O( n^2^ ) c=3; $2n$^2^$-100n-50<=3n$^2^ $n$^2^$>=-100n-50$ $n$^2^$+100n+50>=0$ $n>=1$ | $n$ | $f(n)=2n$^2^$-100n-50$ | $cg(n)=3n$^2^ | | --- |:----------------------:| -------------:| | 1 | $\|-148\|=148$ | 3 | | 2 | $\|-242\|=242$ | 12 | | 3 | $\|-332\|=332$ | 27 | | 4 | $\|-418\|=418$ | 48 | | 5 | $\|-500\|=500$ | 75 | | 10 | $\|-850\|=850$ | 300 | | 15 | $\|-1100 \|=1100$ | 675 | | 20 | $\|-1250\|=1250$ | 1200 | | 21 | $\|-1268\|=1268$ | 1323 | | 23 | $\|-1292\|=1292$ | 1587 | $c=3$ $n_0$$=21$ --- ## :book:第3題:數列被轉置 leetcode 33 * 花費時間:約2小時 * 自己完成程度:完全靠自己 * 思路: 先設定一個新的動態陣列sortedNums,這個是用來儲存排序後的nums,因為已知nums有可能會旋轉i個,如果不排序是沒辦法套用二元搜尋的。 排序之後會有2個情況:有旋轉與沒旋轉 如果沒旋轉的話,我們的location(用於儲存旋轉的數量i)就等於0 有旋轉的話,我們就用一個for迴圈找到sortedNums的第一個數字(也就是最小數字)究竟出現在原本陣列的哪一個位置,然後丟給location,這樣就找到了旋轉的數量。 這一步驟我有試過把for迴圈改成二元搜尋法,然後我寫不出來,我好廢。 然後就可以開始愉快的套用2元搜尋法,不過搜尋的陣列是用已排序的。 找到了目標數字的位置後,精髓來了,因為我們需要知道的是目標數字在原本陣列的位置,而不是排序後的位置 我們可以把原陣列看成一個循環 【4,5,6,7,0,1,2】->【2,4,5,6,7,0,1】->【1,2,4,5,6,7,0】->【0,1,2,4,5,6,7】->【7,0,1,2,4,5,6】..... ![](https://i.imgur.com/6mnfMt8.png) 那我們就可以用cycle queue的概念來看這個情況 我們知道任何數字用mod之後 就會被限定在一個範圍內 那我們的location就是用來表示我前面需要空幾個位置 然後再開始計算位子 那我們怎麼知道我們取餘的數字是多少,因為我們的陣列都是塞滿資料的,那就是直接取陣列裡面有多少個數字就好 我們要做的就是 把留空的位數加上我們在排序後的陣列所得到的數字 去取餘數 於是就得出了(location + middle) % nums.size()這樣的算式 以測資來說 假設我們現在要找的數字是0,那我們的for迴圈取到的location會是4,那我們在排序後的陣列取到目標數字的位子是0 (0+4)%7=4 也就是會變成這樣 ![](https://i.imgur.com/H0XWUF0.png) 那我們有用mod來限制位子 然後讓他形成一個cycle 就變成下面這樣 ![](https://i.imgur.com/jYWNxvm.png) location的目的就是用來留空前面的格子 再加上排序後的目標位子,就得出目標數字在原陣列中的index了。 * 程式碼: ```= #include"iostream" #include<vector> #include<algorithm> using namespace std; class Solution { public: int search(vector<int>& nums, int target) { vector<int>sortedNums = nums; sort(sortedNums.begin(), sortedNums.end()); int location = 0; int resultIndex = -1; if (sortedNums[0] != nums[0]) { for (int i = 0; i < nums.size(); i++) { if (sortedNums[0] == nums[i]) { location = i; break; } } } int left = 0; int right = nums.size() - 1; while (left <= right) { int middle = left + (right - left) / 2; if (sortedNums[middle] == target) { resultIndex = ((location + middle) % nums.size()); break; } else if (sortedNums[middle] < target) { left = middle + 1; } else if (sortedNums[middle] > target) { right = middle - 1; } } return resultIndex; } }; int main() { Solution a; vector<int> nums = {7,8,1,2,3,4,5,6 }; int target = 2; int aa = a.search(nums, target); cout << aa; } ``` * 通過截圖 ![](https://i.imgur.com/aH0nNF8.png) --- ## :book: 第4題:數字可能重複,回傳範圍 leetcode 34 * 花費時間:約1小時半 * 自己完成程度:完全靠自己 * 思路: 題目需要找到指定重複的數字的最開始位置與結束位置,最一開始我看錯題目,以為要輸出全部數字的位置,寫了大概半小時才發現原來只需要頭尾。 我第一次的方式是先找到目標數字的最前面的位置,然後用for迴圈把接下來到結束的位置pushback到vector裡面,然後再回傳,之後發現看錯了之後,我就只是把那個for迴圈改成從目標位置往前以及往後擴散找到最前與最後,可是這樣的方式我覺得會跑很慢,所以我就用兩個二元搜尋,一次是找到最前面,第二次是找到最後面。 * 程式碼: ```= #include"iostream" #include<vector> #include<algorithm> using namespace std; class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { int left=0; int right = nums.size() - 1; int front=-1; int back=-1; while (left <= right &&nums.size()>0) { int middle = left + (right - left) / 2; if (nums[middle] == target) { if (middle <= 0 || nums[middle - 1] != target) { front = middle; break; } else { right = middle - 1; } } else if (nums[middle] < target) { left = middle + 1; } else if (nums[middle] > target) { right = middle-1; } } if(front!=-1)left = front; right = nums.size()-1; while(left<=right && nums.size() > 0) { int middle = left + (right - left) / 2; if (nums[middle] == target) { if (middle >= nums.size() - 1 || nums[middle + 1] != target) { back = middle; break; } else { left = middle + 1; } } else if (nums[middle] < target) { left = middle + 1; } else if (nums[middle] > target) { right = middle - 1; } } vector<int> output = { front,back }; return output; } }; int main() { Solution a; vector<int> nums = {1 }; int target = 3; vector<int> out = a.searchRange(nums, target); printf("[%d,%d]",out[0],out[1]); } ``` * 通過截圖 ![](https://i.imgur.com/xSzvRCI.png) --- ## :book: 第5題:猜數字遊戲 leetcode 374 * 花費時間:約10分鐘 * 自己完成程度:完全靠自己 * 思路: 這題跟上禮拜的其中一題很像(作業5 最早出問題的版本)也是一樣用內建api來寫,在寫的過程中我被題目搞,因為題目的大於小於的判斷的定義,跟右邊寫程式那邊的註解給的定義不同,最一開始我用的是右邊註解的定義,試跑的時候一直錯,再仔細看題目才發現這個問題,哭啊。 * 程式碼: ```= class Solution { public: int guessNumber(int n) { int left=0; int right=n; while(1) { int middle=left+(right-left)/2; int temp=guess(middle); if(temp==-1) { right=middle-1; } else if(temp==1) { left=middle+1; } else return middle; } } }; ``` * 通過截圖 ![](https://i.imgur.com/oY1NN3L.png) --- ## :book: 第6題:請寫下對於本週影片教學和程式作業的適應程度與喜惡。 這次的作業我真的差一點就要去網路找答案了,還好我有堅持下來好好想要怎麼寫,這次的難度比起上禮拜難了很多,可是寫出來之後很爽。 ###### tags: `演算法`