刷了这么多题发现,二分法经常出现,而且运用范围特别广,就像木棒切割问题,矩阵划分等问题。。所以说二分法是必须熟练掌握的,再看几遍未尝不可;
二分查找高效之处在于每一步都可以去除当前区间中的一半元素,因此其时间复杂度为O(log n)。
木棒切割问题:
给出N根木棒,长度均已知,现在希望通过切割他们来得到至少K段长度相等的木棒,问这些长度相等的木棒最长能有多长。
例:三根长度分别为10,24,15的木棒来说,假设K = 7,既需要至少7段长度相等的木棒,那么可以等到的最大长度为 6.
思路:
二分查找;每一个长度值 mid 都会对应一个能分割的最大段数 k,然后判断 k 与 K 的大小,前者大:说明长度(mid)小了 -- > 增大left;后者大 :说明长度(mid)大了 -- > 减小right ;
#include<cstdio>
#include<iostream>
#include<algorithm>
using namespace std;
int main() {
int left, right, mid, k, K, N, a[1005];
scanf("%d",&N);
for(int i = 0; i < N; i++){
scanf("%d",&a[i]);
}
scanf("%d",&K);
sort(a, a + N);
left = 0, right = a[N - 1];
while(left < right){
mid = (left + right) / 2;//如果left + right 超 int可以写成,left + (right - left)/ 2;
k = 0;
for(int i = 0; i < N; i++){
k += a[i] / mid;
}
if(k < K) right = mid;
else left = mid + 1;
}
printf("%d\n",right - 1);
return 0;
}
经典问题模板:
(1)查找 X 。
int binarySearch(int A[], int left, int right, int x){
int mid;
while(left <= right){
mid = (left + right) / 2;
if(A[mid] == x) return mid;
if(A[mid] > x) right = mid - 1;
else left = mid + 1;
}
return -1;
}
(2)查找第一个大于等于 X 元素的位置。
int lower_bound(int A[], int left, int right, int x){
int mid;
while(left < right){
mid = (left + right) / 2;
if(A[mid] >= x) right = mid;
else left = mid + 1;
}
return left;
}
(3)查找第一个大于 X 元素的位置。
int upper_bound(int A[], int left, int right, int x){
int mid;
while(left < right){
mid = (left + right) / 2;
if(A[mid] > x) right = mid;
else left = mid + 1;
}
return left;
}