---
# System prepended metadata

title: Algo-hw2
tags: [Algorithm]

---

# 演算法作業二

## 觀念題

-   第1題:  Prove $f(n) = 4n^3 - 5n + 6$
	:::info
	$f(n) >= 5n^3\space\forall\space n>=1$
	so, $f(n) = O(n^3)$
	Q.E.D.
	:::
	
-   第2題:  Prove $f(n) = 30n^2 - 100n -50$
	:::info
	$|f(n)| >= 31n^2\space \forall\space n>=3$
	so, $f(n) = O(n^2)$
	Q.E.D.
	:::
-   第3題:  Prove $f(n) = 5n^4 - 10n + 6$
	:::info
	$f(n) >= 6n^4 \space \forall \space n>=1$
	so,$f(n) =O(n^4)$
	Q.E.D.
	:::
	

## 程式題

### 第三題：數列被轉置
[leetcode 33](https://leetcode.com/problems/search-in-rotated-sorted-array/)
- 程式碼
	:::spoiler C++
	```c++= 
	class Solution {
	public:
		int search(vector<int>& nums, int target) {
			int left  = 0;
			int right = nums.size()-1;

			while (left<=right){
				int mid = left + (right - left) / 2;

				if (target == nums[mid])
					return mid;

				if (nums[left] <= nums[mid]){
					// May Not Be Rotated
					if ( nums[left] <= target && target <= nums[mid] ){
						// target is in left to mid
						right = mid - 1;
					}
					else{
						//target is not in left to mid
						left = mid + 1;
					}

				}
				else{
					//May Not Rotated
					if ( nums[mid] <= target && target <= nums[right] ){
						// target is in mid to right
						left = mid + 1;
					}
					else{
						//target is not in mid to right
						right = mid - 1;
					}
				}
			}
			return -1;
		}
	};
	```
	:::
- 執行結果
	![image](https://hackmd.io/_uploads/S1Io3lh36.png)
- 程式語言：C++
- 花費時間：20分鐘
- 完成程度：有上網看思路
	- ref 1 ：[ref](https://leetcode.com/problems/search-in-rotated-sorted-array/solutions/3879263/100-binary-search-easy-video-o-log-n-optimal-solution)
- 思路：
	1. 這題可能包含無旋轉的array
	2. 所以我們可以簡單的把陣列拆成兩部分
		:::info
		###### 以測試資料1為例
		![image](https://hackmd.io/_uploads/SJcXlb3np.png)
		- 將陣列分成兩個，**向左遞減與向右遞增**進行討論
		:::
	3. 判斷搜索範圍是否為**向左遞減與向右遞增**進如下
		- 向右遞增：`nums[left] <= nums[mid]`
		- 向左遞減：`nums[left] > nums[mid`
	4. 最後，我們只要用二分搜的方式就可以求解了
		- 向右遞增
			- `target`是否在`[left...mid]`之間 => `right = mid -1`
			- 否則 => `left = mid + 1`
		- 向左遞減
			- `target`是否在`[mid...rigjt]`之間 => `left = mid + 1`
			- 否則 => `right = mid - 1`
		
### 第四題：數字可能重複，回傳範圍
[leetcode 34](https://leetcode.com/problems/find-first-and-last-position-of-element-in-sorted-array/)
- 程式碼
	:::spoiler C++
	```c++=
	class Solution {
	public:
		vector<int> searchRange(vector<int>& nums, int target) {
			vector<int>ans(2);

			ans[0] = lowerBound(nums, target);
			ans[1] = upperBound(nums, target);

			return ans;
		}

	private:
		int lowerBound(vector<int>& nums, int target){
			int left  = 0;
			int right = nums.size() - 1;

			int ans = -1;
			while (left <= right){
				int mid = left + (right - left) / 2;

				if (nums[mid] < target){

					left = mid + 1;
				}
				else{
					right = mid - 1;
					ans   = mid;  
				}
			}
			if (ans == -1) return -1;
			return nums[ans] == target?ans:-1;
		}


		int upperBound(vector<int>& nums, int target){
		   int left  = 0;
			int right = nums.size() - 1;

			int ans = -1;
			while (left <= right){
				int mid = left + (right - left) / 2;

				if (nums[mid] <= target){

					left = mid + 1;
					ans   = mid;
				}
				else{
					right = mid - 1;

				}
			}
			if (ans == -1) return -1;
			return nums[ans] == target?ans:-1;
		}
	};
	```
	:::
- 執行結果
	![image](https://hackmd.io/_uploads/S1FRG-2np.png)
- 程式語言：C++
- 花費時間：10分鐘
- 完成程度：靠自己
- 思路
	1. 這題跟上周題目很像，是求出lowerbound 跟 upperbound
	2. 所以我會拿ans值迭代的紀錄可能的答案值
	3. 最後回傳答案
### 第五題: 猜數字遊戲
[leetcode 374](https://leetcode.com/problems/guess-number-higher-or-lower/description/)
- 程式碼
	:::spoiler C++
	```c++=
	class Solution {
	public:
		int guessNumber(int n) {
			int left = 1;
			int right = n;

			while(left<=right){
				int mid = left + (right - left) / 2;

				if (!guess(mid)){
					return mid;
				}
				else if (guess(mid) == 1){
					left = mid + 1;
				}
				else{
					right = mid - 1;
				}
			}
			return -1;
		}
	};
	```
	:::
- 執行結果
	![image](https://hackmd.io/_uploads/r1-C4W32T.png)
- 程式語言：C++
- 花費時間：5分鐘
- 完成程度：靠自己
- 思路：
	- 這題高中就有稍微聽過類似的了，其實就是二分搜
	- 分成幾個情況討論：
		- 比猜的數字大：則`right = mid - 1`
		- 跟猜的數字一模一樣，則`return mid`
		- 比猜的數字小，則`left = mid + 1`
### 第六題: 找出正數或負數的數量較大者
[leetcode 2529](https://leetcode.com/problems/maximum-count-of-positive-integer-and-negative-integer/)
- 程式碼
	:::spoiler C++
	```c++=
	class Solution {
	public:
		int maximumCount(vector<int>& nums) {
			int left = 0;
			int right = nums.size() - 1;

			int lower = lowerBound(nums,0);
			int upper = nums.size() - upperBound(nums,0);
			return std::max(lower,upper);
		}
	private:
		int lowerBound(vector<int>& nums, int target){
			int left  = 0;
			int right = nums.size() - 1;

			while (left <= right){
				int mid = left + (right - left) / 2;

				if (nums[mid] >= target){
					right = mid - 1;
				}
				else{
					left = mid + 1;
				}
			}

			return left;
		}


		int upperBound(vector<int>& nums, int target){
			int left  = 0;
			int right = nums.size() - 1;

			while (left <= right){
				int mid = left + (right - left) / 2;

				if (nums[mid] > target){
					right = mid - 1;
				}
				else{
					left = mid + 1;
				}
			}

			return left;
		}
	};
	```
	:::
- 執行結果
	![image](https://hackmd.io/_uploads/B1PB4znhp.png)
- 程式語言：C++
- 花費時間：20分鐘
- 完成程度：靠自己
- 思路：
	~~話說我後來發現這題測資的測資用線搜還比較快~~
	1. 這題跟第四題很像，都是找lowerBound與upperBound
	2. 我們簡化題目
		- 先找0的upperBound和lowerBound
		- 再從剛剛的答案算出所求
	3. 實際例子
		:::info
		###### 以測資一為例子
		![image](https://hackmd.io/_uploads/B1TIrG2nT.png)
		###### 以測資二為例
		![image](https://hackmd.io/_uploads/SyahSfh36.png)
		:::
		- 這樣可以統整出
			- $negaive = lower$
			- $positive = size - upper$
	4. 最後`return std::max(negative,Positive)`即可

## 心得
這周跟上周一樣都是二分搜，有幾題比較印象深刻，第三題跟最後一題，是我想最久的題目，我覺得那幾題有點抽象，我要拿紙筆推才解出來。

這周的課程在講時間複雜度，老實說之前計概有學過，但我到現在才知道原本的假設是$f(n)>=0$，我覺得蠻特別的o.O。