---
# System prepended metadata

title: 演算法 二元搜尋法（續）
tags: [演算法]

---

# 演算法 二元搜尋法（續）

## :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: `演算法`


