在看到一个求最佳答案的题没有思路的时候可以直接套这个二分法找最值
这个模板有两个函数,一个是check()用于在二分查找中对是否成立进行判断,还有一个就是常规的二分查找算法(稍稍改进一下)
直接上模板!
定义
int l = 0, r = 1e9;
int mins = 0, maxs = 0;
void searchmax()
{
while (l < r)
{
int mid = (r + l) / 2;
if (check(mid))
{
maxs = mid;
l = mid+1;
}
else
r = mid ;
}
}
void searchmin()
{
while (l < r)
{
int mid = (r + l) / 2;
if (check(mid))
{
mins = mid;
r = mid;
}
else
l=mid+1;
}
}
上面部分是找最大值,下面部分是找最小值,check()函数的功能就是对这个mid值代入检验(满不满足题目的要求)。
上限l直接定义到题目的最大范围,下限的r可能是1也可能是0,注意看题!
查找过程:
假设我们要找的最大值是6,r是20,l是1 (合法数据范围3~6)
第一次二分查找:mid=10,把10传入check()函数进行判断,不满足返回0,执行else语句,r=9(因为这个mid不满足题目条件,所以范围需要缩小,此时r=10,l=1)
第二次二分查找:mid=5,把5传入check()函数进行判断,满足返回1,执行if语句,先记录下mid的值,l=6(增加下限l的值,如果符合条件就增大mid的值,寻找最大值,此时r=10,l=6)
第三次二分查找:mid=7,把7传入check()函数进行判断,不满足返回0,执行else语句,r=6(因为这个mid不满足题目条件,所以范围需要缩小,此时r=7,l=6)
第四次二分查找:mid=6,把6传入check()函数进行判断,满足返回1,执行if语句,先记录下mid的值,l=7(增加下限l的值,如果符合条件就增大mid的值,寻找最大值,此时r=7,l=7)
此时不满足l<r这个循环条件,退出循环,已找到最大值maxs
思路:
首先进行二分查找,尽可能的缩小查找范围,但只要找到了一个满足题意的数据,立即提高mid的值,往上查找,一但出现不符合题意的数据,就缩小mid的值往下查找,最终找到在合法数据内满足题意条件的最大值。(一句话:只要满足就扩大,只要不满足就缩小,用二分法写算法题基本上都不会超时)
查找最小值的过程:
假设l=1,r=6,最小值为2(r为查找到的最大值,缩小查找范围)
第一次二分查找:mid=3,把3传入check()函数进行判断,满足返回1,执行if语句,先记录下mid的值,r=3(减少上限r的值,如果符合条件就减小mid的值,寻找最小值,此时r=3,l=1)
第二次二分查找:mid=2,把2传入check()函数进行判断,满足返回1,执行if语句,先记录下mid的值,r=2(减少上限r的值,如果符合条件就减小mid的值,寻找最小值,此时r=2,l=1)
第三次二分查找:mid=1,把1传入check()函数进行判断,不满足返回0,执行else语句,l=2(因为这个mid不满足题目条件,所以范围需要扩大,增加l的值,此时r=2,l=2)
此时不满足l<r这个循环条件,退出循环,已找到最大值mins
思路:
和找最大值一样,区别就是把最大值当作查找的上限(省时间),只要满足就缩小范围,只要不满足就扩大范围。
对于check(int mid)函数来说,如果传入的mid符合题意,返回1,否则返回0。
这种算法查找适合这种情况
第二种是单独找最小值的情况
随便一个比较大的数据都满足,满足题意的数据的最大值可以是随便一个大数字,范围是这样的
直接上代码模板
int l = 0, r = 2e9;
int mins = 0, maxs = 0;
void searchmin()
{
while (l < r)
{
int mid = (r + l) / 2;
if (check(mid))
{
mins = mid;
r = mid;
}
else
l=mid+1;
}
}
和上面的二分法找最小值的思路都是一样的,只是r的范围不一样,也是对二分查找法的一个运用
check()函数也还是判断这个数据是否符合题意。