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!
BinarySearch
By Wu Phoebe
BinarySearch
- 115