---
# System prepended metadata

title: 演算法作業 HW02
tags: [演算法作業]

---

###### tags: `演算法作業`
# 演算法作業 HW02
## 觀念題
![](https://i.imgur.com/qhrSMAM.png)
### 1. ![](https://i.imgur.com/NNleFAt.png)
- ![](https://i.imgur.com/CyLLgMf.png)

### 2. ![](https://i.imgur.com/oSg3Y1E.png)
- ![](https://i.imgur.com/d3QgHbV.png)




## 程式題(延續二元搜尋)
### 3. 數列被轉置(LeetCode 33)
- 程式碼 : 
```C++=
class Solution { 
public:
    int search(vector<int>& nums, int target) {
        int left = 0,right = nums.size()-1;
        int mid = 0;
        while(left <= right){
            mid = left + (right-left)/2;
            if(nums[mid] == target){
                return mid;
            }
            if(nums[mid] > nums[right]){
                //最左數到中間數為升序
                if(nums[mid] > target && nums[left] <= target){
                    right = mid -1;
                }else{
                    left = mid +1;
                }
            }else{
                //nums[mid] < nums[right]
                //中間數到最右數為升序
                if(nums[mid] < target && nums[right] >= target){
                    left = mid +1;
                }else{
                    right = mid -1;
                }
            }
        }
        return -1;
    }
};
```
- 測試輸出輸入的畫面 : ![](https://i.imgur.com/zkjaokR.png)

- 花費的時間 : 1 **hr** 50 **min**
- 完成的程度 : 解題思路完全靠自己想，Test完後輸出結果錯誤，上網找哪裡想法錯誤，發現沒有考慮如果最左值或最右值是Target會怎麼樣。
- 解題思路 : 
  - 數列旋轉仍有序(不確定中點前或中點後)
  - 二分關鍵 獲得中間值 決定向左向右
  - ![](https://i.imgur.com/t4fibYP.png) ![](https://i.imgur.com/5d3ocNl.png)
    - 發現中間數大於最右數，最左數到中間數為升序。
      (中間數大於最左數也可 但中間數"可能等於"最左數")
        - 如果中間數 == Target，return mid
        - 如果中間數 < Target，left = mid +1
        - 如果中間數 > Target，需判斷最左數
            - 若最左數 <= Target，right = mid-1
            - 若最左數 > Target，left = mid+1

    - 發現中間數小於最右數，中間數到最右數為升序。
      (中間數小於最左數也可 但中間數"可能等於"最左數")
      - 如果中間數 == Target，return mid
      - 如果中間數 < Target，需判斷最右數
        - 若最右數 <= Target，left = mid+1
        - 若最右數 > Target，right = mid-1
      - 如果中間數 > Target，right = mid-1
      
### 4. 數字可能重複，回傳範圍(LeetCode 34)
- 程式碼 : 
```C++=
class Solution {
public:
    vector<int> searchRange(vector<int>& nums, int target) {
        vector<int> ans;
        ans.push_back(preSearch(nums, target));
        ans.push_back(postSearch(nums, target));
        return ans;
    }
    
    int preSearch(vector<int>& nums, int target){
        int left = 0;
        int right = nums.size()-1;
        int mid =0;
        if(nums.size() == 0){
            return -1;
        }
        while(left < right){
            mid = left + (right-left)/2;
            if(nums[mid] >= target){
                right = mid;
            }else{
                left = mid +1;
            }
        }
        if(nums[left] == target){
            return left;
        }else{
            return -1;
        }
    }
    int postSearch(vector<int>& nums, int target){
        int left = 0;
        int right = nums.size()-1;
        int mid =0;
        if(nums.size() == 0){
            return -1;
        }
        while(left < right){
            mid = left + (right-left)/2 +1;
            if(nums[mid] <= target){
                left = mid;
            }else{
                right = mid -1;
            }
        }
        if(nums[left] == target){
            return left;
        }else{
            return -1;
        }
    }
};
```
- 測試輸出輸入的畫面 : ![](https://i.imgur.com/B2xdRmE.png)

- 花費的時間 : 10 **min**
- 完成的程度 : 完全靠自己
- 解題思路 : 
    - 雖然有重複 但是按照大小排列
    - 可聯想到 **演算法作業 HW01 第3題**
    - 中間值"可能"會等於left 所以在postSearch中間值需加1 否則會陷入迴圈
    - 數字可能為null，先判斷長度是否為0，若是直接回傳-1。
### 5. 猜數字遊戲(LeetCode 374)
- 程式碼 : 
```C++=
/** 
 * Forward declaration of guess API.
 * @param  num   your guess
 * @return 	     -1 if num is lower than the guess number
 *			      1 if num is higher than the guess number
 *               otherwise return 0
 * int guess(int num);
 */
 /** 
 * Forward declaration of guess API.
 * @param  num   your guess
 * @return 	     -1 if num is lower than the guess number
 *			      1 if num is higher than the guess number
 *               otherwise return 0
 * int guess(int num);
 */

class Solution {
public:
    int guessNumber(int n) {
        int left = 1,right = n;
        int mid = 0;
        while(left <= right){
            mid = left + (right-left)/2;
            if(guess(mid) == -1){
                //比mid 小
                right = mid -1; 
            }else if(guess(mid) == 1){
                //比mid 大
                left = mid +1;
            }else{
                //guess(mid) == 0 猜中
                return mid;
            }
        }
        return mid;
    }
};
```
- 測試輸出輸入的畫面 : ![](https://i.imgur.com/ST0n59v.png)

- 花費的時間 : 10 **min**
- 完成的程度 : 完全靠自己
- 解題思路 : 
    - 終極密碼 二分法
    - guess(num) 
        - return -1 ,比mid 小,right = mid -1; 
        - return 1  ,比mid 大,left = mid +1;
        - return 0  ,成功猜中,return mid;
                
## 心得
### 6. 請寫下對於本週影片教學和程式作業的適應程度與喜惡。
- 老師講得很明白，我也完全可以聽懂。
- 第3題想了好久(大概有1hr在畫那張圖找規律)，曾試過找中間值左右兩邊會有固定的規律，後來發現按照升冪排序找到規律，最後找到規律還是很有成就感。相比第3題 4.5簡單許多。
- 還蠻適應的，第3題沒有特別找到更好的方法
