Binary Search

吳若喬

Index

Recursion         review

簡單統整:
  • 在函式裡面再呼叫自己
  • 可根據需求宣告void或是int
  • 注意邊界處理否則會跳不出遞迴
//範例:階乘的遞迴函式
int Factorial(int n){
    if(n==1){
    	return 1; //終止條件
    }
    else{
    	return n*Factorial(n-1); //呼叫自己
    }
}

BinarySearch

Introduction

1 2 3 4 5 6 7 8 9 10

假設有一陣列包含以下內容:

BinarySearch

Introduction

1 2 3 4 5 6 7 8 9 10

假設有一陣列包含以下內容:

尋找2是否在此序列內

1 2 3 4 5 6 7 8 9 10

依序搜尋?

#include <bits/stdc++.h>
using namespace std;

int main() {
	int num[10]={1,2,3,4,5,6,7,8,9,10};
	int goal=2,times=0;
	for(int i=0;i<10;i++){
		times++;
		if(num[i]==goal){
			cout << goal << "在此序列中" << endl;
			cout << "找了" << times << "次";
		}
	}
	return 0;
}
1 2 3 4 5 6 7 8 9 10

如果要找9呢?

#include <bits/stdc++.h>
using namespace std;

int main() {
	int num[10]={1,2,3,4,5,6,7,8,9,10};
	int goal=9,times=0;
	for(int i=0;i<10;i++){
		times++;
		if(num[i]==goal){
			cout << goal << "在此序列中" << endl;
			cout << "找了" << times << "次";
		}
	}
	return 0;
}
1 2 3 4 5 6 7 8 9 10

如果今天陣列開了10000個.....

可想而知 依序尋找是很沒效率的方法

1 2 3 4 5 6 7 8 9 10

找2

1 2 3 4 5 6 7 8 9 10

找2

2<5

1 2 3 4 5 6 7 8 9 10

找2

切一半

1 2 3 4 5 6 7 8 9 10

找2

1 2 3 4 5 6 7 8 9 10

找2

2<3

1 2 3 4 5 6 7 8 9 10

找2

切一半

1 2 3 4 5 6 7 8 9 10

找2

1 2 3 4 5 6 7 8 9 10

找2

找到了!

必須先排序好才可以進行二分搜!

求最佳解

有N塊木頭,給你K次切割的機會,請求出最長的那塊可以是多少?

求最佳解

有N塊木頭,給你K次切割的機會,請求出最長的那塊可以是多少?(小數點無條件進位)

input:

2

7 9

3

求最佳解

有N塊木頭,給你K次切割的機會,請求出最長的那塊可以是多少?(小數點無條件進位)

思路:

先把所有木塊盡可能分小塊並算出要幾刀才能達成

如果大於K就代表不符合,一直把標準放寬直到符合K

 

前提:

最小值只可能是1因為無條件進位不可能為0

模擬一遍(以無條件進位計算):


不超過1 -> 7:7、9:9 -> 7+9 > 3

不超過2 -> 7:4、9:5 ->4+5 > 3

.

.

.

.

模擬一遍(以無條件進位計算):


不超過1 -> 7:7、9:9 -> 7+9 > 3

不超過2 -> 7:4、9:5 ->4+5 > 3

.

.

.

.

有沒有很眼熟?這跟之前找數字幾乎一模一樣

但同樣的順著找太累了 所以我們請二分搜幫忙

模擬一遍(以無條件進位計算):


不超過1 -> 7:7、9:9 -> 7+9 > 3

不超過2 -> 7:4、9:5 ->4+5 > 3

.

.

.

.

有沒有很眼熟?這跟之前找數字幾乎一模一樣

但同樣的順著找太累了 所以我們請二分搜幫忙

#include <bits/stdc++.h>

using namespace std;
// 檢查現在猜的 X 有沒有機會達成要求
bool check(int X, int K, vector<int> &logs) {
    int count = 0;
    for (vector<int>::iterator log=logs.begin();log!=logs.end();log++) {
        count += (ceil((double)*log / X) - 1);
        if (count > K) {
            return false;
        }
    }
    return true;
}
int main() {
    // 設定題目資料
    long long int N = 2, K = 3,times=0;
    vector<int> logs = {7, 9};
    // Binary Search
    int left = 1, right = pow(10,3); //看題目增加上限
    while (left <= right) {
        int mid = (left + right) / 2;
        if (check(mid, K, logs)) {
            right = mid - 1;
        } else {
            left = mid + 1;
        }
    }
    cout << left << endl; 
    return 0;
}

BinarySearch

Coding

#include <bits/stdc++.h>
using namespace std;

int main() {
	int num[10];
	int mid=5,left=0,right=9;
	for(int i=0;i<10;i++){
		cin >> num[i];
	}
	sort(num,num+10);//greater<int>()
	for(int i=0;i<10;i++){
		cout << num[i] << " ";
	}
	cout << endl;
	int goal;
	cin >> goal;
	while(left<=right){
		if(num[mid]<goal){
			left=mid+1;
		}else if(num[mid]>goal){
			right=mid-1;
		}
		mid=(left+right)/2;
		if(num[mid]==goal){
			cout << "該數字在此序列中" << endl;
			return 0;
		}
		
	}
	cout << "該數字不在此序列中" << endl;
	return 0;
}
int num[10];
int mid=5,left=0,right=9;
for(int i=0;i<10;i++){
	cin >> num[i];
}
sort(num,num+10);//greater<int>()
for(int i=0;i<10;i++){
	cout << num[i] << " ";
}
cout << endl;
int goal;
cin >> goal;
  • 宣告陣列
  • 指定範圍用於切割
  • 如果陣列大小未知使用sizeof計算陣列長度mid=(right+left)/2 無條件捨去小數位
int num[10];
int mid=5,left=0,right=9;
for(int i=0;i<10;i++){
	cin >> num[i];
}
sort(num,num+10);//greater<int>()
for(int i=0;i<10;i++){
	cout << num[i] << " ";
}
cout << endl;
int goal;
cin >> goal;
  • 輸入
int num[10];
int mid=5,left=0,right=9;
for(int i=0;i<10;i++){
	cin >> num[i];
}
sort(num,num+10);//greater<int>()
for(int i=0;i<10;i++){
	cout << num[i] << " ";
}
cout << endl;
int goal;
cin >> goal;
  • 排序
int num[10];
int mid=5,left=0,right=9;
for(int i=0;i<10;i++){
	cin >> num[i];
}
sort(num,num+10);//greater<int>()
for(int i=0;i<10;i++){
	cout << num[i] << " ";
}
cout << endl;
int goal;
cin >> goal;
  • 指定要找的數字
while(left<=right){
	if(num[mid]<goal){
		left=mid+1;
	}else if(num[mid]>goal){
		right=mid-1;
	}
	mid=(left+right)/2;
	if(num[mid]==goal){
		cout << "該數字在此序列中" << endl;
		return 0;
	}
		
}
  • 需要符合"左邊的索引值小於等於右邊索引值"
  • 不符合就是找不到
while(left<=right){
	if(num[mid]<goal){
		left=mid+1;
	}else if(num[mid]>goal){
		right=mid-1;
	}
	mid=(left+right)/2;
	if(num[mid]==goal){
		cout << "該數字在此序列中" << endl;
		return 0;
	}
		
}
  • 因為有排序過,可以由目前的數字判斷要往上還是往下移動

mid+1 or mid-1?

1 2 3 4 5 6 7 8 9 10

mid+1 or mid-1?

1 2 3 4 5 6 7 8 9 10

goal

mid

left

right

mid+1 or mid-1?

1 2 3 4 5 6 7 8 9 10

goal

mid

left

right

  • 4<5 所以要讓整體往左忽略右半
  • 所以右邊的索引值要更動

mid+1 or mid-1?

1 2 3 4 5 6 7 8 9 10

goal

left

right

if(num[mid]<goal){
	left=mid+1;
}else if(num[mid]>goal){
	right=mid-1;
}
while(left<=right){
	if(num[mid]<goal){
		left=mid+1;
	}else if(num[mid]>goal){
		right=mid-1;
	}
	mid=(left+right)/2;
	if(num[mid]==goal){
		cout << "該數字在此序列中" << endl;
		return 0;
	}
		
}
  • 因為左右範圍有改,中間的索引值也要進行更動

BinarySearch

Recursion

int BinarySearch(int arr[],int first,int last,int value){
    int mid=(first+last)/2;   
    if(first==last && value!=arr[mid]) 
    	return -1;
    if (value==arr[mid]) 
    	return mid;
    else if (value>arr[mid]) 
    	return BinarySearch(arr,mid+1,last,value);
    else return BinarySearch(arr,first,mid-1,value);
}
int BinarySearch(int arr[],int first,int last,int value){
    int mid=(first+last)/2;   
    if(first==last && value!=arr[mid]) 
    	return -1;
    if (value==arr[mid]) 
    	return mid;
    else if (value>arr[mid]) 
    	return BinarySearch(arr,mid+1,last,value);
    else return BinarySearch(arr,first,mid-1,value);
}
  • 計算中點
int BinarySearch(int arr[],int first,int last,int value){
    int mid=(first+last)/2;   
    if(first==last && value!=arr[mid]) 
    	return -1;
    if (value==arr[mid]) 
    	return mid;
    else if (value>arr[mid]) 
    	return BinarySearch(arr,mid+1,last,value);
    else return BinarySearch(arr,first,mid-1,value);
}
  • 如果兩點重合仍不是要找的數字就代表不在此序列
int BinarySearch(int arr[],int first,int last,int value){
    int mid=(first+last)/2;   
    if(first==last && value!=arr[mid]) 
    	return -1;
    if (value==arr[mid]) 
    	return mid;
    else if (value>arr[mid]) 
    	return BinarySearch(arr,mid+1,last,value);
    else return BinarySearch(arr,first,mid-1,value);
}
  • 回傳要找的數字
int BinarySearch(int arr[],int first,int last,int value){
    int mid=(first+last)/2;   
    if(first==last && value!=arr[mid]) 
    	return -1;
    if (value==arr[mid]) 
    	return mid;
    else if (value>arr[mid]) 
    	return BinarySearch(arr,mid+1,last,value);
    else return BinarySearch(arr,first,mid-1,value);
}
  • 大於或小於的判斷 寫法和迴圈的都一樣 -> 較大改變左邊界、較小改變左邊界

Kahoot!

Made with Slides.com