二分搜尋有隨機訪問的特性,在數組是有序的情況下,透過訪問的元素,推測左右兩側的性質,展現較高的效率。
以下整理己主以下整理幾種解題時會出現的模板
//標準的二分搜尋
int find_target(const int& target, const vector<int>& arr){
int f = 0;
int b = arr.size()-1;
while(b>=f){
int mid = (b+f)/2; //中點
if(arr[mid]==target){
return mid;
}
if(arr[mid]>target){ //目前的mid>target,要尋找的值應該在左側
b = mid-1; //已經確定mid不是target, 可以從mid-1移動b
}
if(arr[mid]<target){ //要尋找的值應該在右側
f = mid+1; //已經確定mid不是target, 可以從mid+1移動f
}
}
return -1; //not found
}
//應對沒有搜尋到目標,返回比目標大的值其索引
int find_target_return_f(const int& target, const vector<int>& arr){
int f = 0;
int b = arr.size()-1;
while(b>=f){
int mid = (b+f)/2;
if(arr[mid]==target){
return mid;
}
if(arr[mid]>target){
b = mid-1;
}
if(arr[mid]<target){
f = mid+1;
}
}
return f; //not found
//return b; // -->返回比目標小的值其索引
}
//返回較大索引的另一種寫法
int find_target_return_bigger(const int& target, const vector<int>& arr){
int f = 0;
int b = arr.size()-1;
while(b>f){ //這邊要改寫成沒有等號,以免會無限循環(b==f時)
int mid = (b+f)/2; //中點
if(arr[mid]==target){
return mid;
}
if(arr[mid]>target){ //因目的是返回比目標大的最小索引,此處mid可能是答案,保留,尋找更小的索引
b = mid;
}
if(arr[mid]<target){
f = mid+1; //若小於target不符合規定,f不可能是答案,直接移動至mid+1
}
}
return b;
}
有了模板之後就可以開始刷題了
1482. 制作 m 束花所需的最少天数
編寫achievable檢查後,以二分搜尋法帶入
((暴力法一一帶入;速度太慢))
class Solution {
public:
int minDays(vector<int>& bloomDay, int m, int k) {
//[暴力法]超時
// vector<int> hash = bloomDay;
// sort(hash.begin(), hash.end());
// int res = -1;
// for(int i = 0; i<hash.size(); i++){
// res = hash[i];
// int cnt = 0;
// int contin = 0;
// for(int j = 0; j<bloomDay.size(); j++){
// if(bloomDay[j]<=res){
// contin++;
// if(contin==k){
// cnt++;
// contin = 0;
// }
// }
// else{
// contin = 0;
// }
// if(cnt==m){
// return res;
// }
// }
// }
// return -1;
//[二分搜尋法]優化通過
int mmax = -1;
for(int i = 0; i<bloomDay.size(); i++){
mmax = max(bloomDay[i], mmax);
}
int res = -1;
int b = mmax;
int f = 0;
while(b>=f){
int mid = (f+b)/2;
if(achievable(bloomDay, m, k, mid)){
res = mid;
b = mid-1;
}
else{
f = mid+1;
}
}
return res;
}
bool achievable(vector<int>& bloomDay, int m, int k, int day){
int cnt = 0;
int contin = 0;
for(int i = 0; i<bloomDay.size(); i++){
if(bloomDay[i]<=day){
contin++;
-----
if(contin==k){
cnt++;
contin = 0;
}
}
else{
contin = 0;
}
if(cnt==m){
return true;
}
}
return false;
}
};
這題之前有放過了,再提一次==刷了兩次還是會沒想法
162. 寻找峰值
if nums[mid]>nums[mid+1] 則 [mid+1 ~ N]必有峰值
class Solution {
public:
int findPeakElement(vector<int>& nums) {
int f = 0;
int b = nums.size()-1;
int mid = -1;
while(b>f){
mid = (f+b)/2;
if(nums[mid]>nums[mid+1]){
b = mid;
}
else{
f = mid+1;
}
}
return f;
}
};