二分算法
一、前言
今天又是一个优化算法------二分算法
二、二分
2.1 概述
在一个有序数组中查找一个数。
每次考察数组当前部分的中间元素,如果中间元素刚好是要找的,就结束搜索过程;如果中间元素小于所查找的值,那么左侧的只会更小,不会有所查找的元素,只需到右侧查找;如果中间元素大于所查找的值,同理,只需到左侧查找。
2.2 代码
cpp
int binarySearch(int a[],int size,int target)
{
int l=0,r=size-1;
int ans=-1;
while(l<=r)
{
int mid=l+(r-l)/2;
if(a[mid]>=target)
{
ans=mid;
r=mid-1;
}
else
{
l=mid+1;
}
}
return ans;
}
注意
- 不能背板子,二分很++灵活++!!!
- 边界条件(while循环条件)是和循环内容配套的,很容易写着写着陷入死循环
时间复杂度 :O(logn)
2.3 常见题型
-
查找某个数的位置
洛谷:P2249 【深基13.例1】查找
-
枚举答案,但降低时间复杂度,判断一个解是否可行(猜答案)
-
最小化最大值/最大化最小值以及其他求最值问题 ★
洛谷
- P2678 [NOIP 2015 提高组] 跳石头(最大化最小值)
- P1873 [COCI 2011/2012 #5] EKO / 砍树(最大化最小值)
- P1824 [USACO05FEB] 进击的奶牛 Aggressive Cows G(最大化最小值)
leetcode:875.爱吃香蕉的珂珂(最小化最大值)
解题过程
- 无论是最小化最大值还是最大化最小值,先明白题目让求的是什么
- 确定答案区间,二分答案(确定二分的区间),假设mid就是答案
- 接着根据题设条件(题目中的其他参数)继续和mid比较,更新mid,最终得解
2.4 补充
在C++头文件algorithm中,有两个函数底层就是二分,在解题中使用起来很方便
cpp
#include<algorithm>
// qian'd
lower_bound(arr.begin(), arr.end(), val);
// 在[begin, end)中找到第一个位置并返回其地址,使得val插入在这个位置前面
upper_bound(arr.begin(), arr,end(), val);
// 在[begin, end)中找到最后一个位置并返回其地址,使得val插入在这个位置前面
三、小结
关于二分,一定要注意循环条件,不然容易陷入死循环
本篇结合灵神题单,洛谷官方书籍等以及我自己的见解而来~