二分(整数二分和浮点数二分)
基础算法——二分(整数二分和浮点数二分)目录
二分(整数二分和浮点数二分)
整数二分
知识点
有单调性一定可以二分,可以二分不一定有单调性
二分的本质是右半边满足这种性质,左半边不满足这种性质
如果可以找到这样一种性质,使数组一分为二,即可以找到边界点位置
二分左半边的右边界点
1.步骤
1.找中间值 mid=(l+r+1)/2
2.判断中间值是否满足性质
假设性质是左半边的性质
if(check(mid)){
mid在左半区间,所以要寻找的边界点范围为**[mid,r]**
因为mid可能为左半边的右边界点即要寻找的边界点,所以左闭
即**更新 l=mid**
}
else{
mid在右边区间,所以要寻找的边界点范围为**[l,mid-1]**
因为mid不满足左半边的性质,所以mid不可能是左半边的右边界点,所以右边取不到mid
即**更新 r=mid-1**
}
2.代码(带注释)
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
bool check(int x) {/* ... */} // 检查x是否满足左半边性质性质
int zs_erfen_1(int l, int r) // 整数二分模板1
{
while (l < r){
int mid = (l + r + 1) >> 1; //当l=mid这种情况时 中间值要补上+1 例如当l=r-1时,mid=l,此时如果check为true,会出现死循环,正常应该mid=r,所以要+1
if (check(mid)){
l = mid;
}
else{
r = mid - 1;
}
}
return l;
}
3.代码(不带注释)
// 区间[l, r]被划分成[l, mid - 1]和[mid, r]时使用:
bool check(int x) {
}
int zs_erfen_1(int l, int r)
{
while (l < r){
int mid = (l + r + 1) >> 1;
if (check(mid)){
l = mid;
}
else{
r = mid - 1;
}
}
return l;
}
二分右半边的左边界点
1.步骤
1.找中间值 mid=(l+r)/2
2.判断中间值是否满足性质
假设性质是右半边的性质
if(check(mid)){
mid在右边区间,所以要寻找的边界点范围为**[l,mid]**
因为mid不满足左半边的性质,所以mid可能是右半边的左边界点,所以右闭
即**更新 r=mid**
}
else{
mid在左半区间,所以要寻找的边界点范围为**[mid+1,r]**
因为mid不可能为右半边的左边界点即要寻找的边界点,所以取不到mid
即**更新 l=mid+1**
}
2.代码(带注释)
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
bool check(int x) {/* ... */} // 检查x是否满足右半边性质
int zs_erfen_2(int l, int r) // 整数二分模板2
{
while (l < r){
int mid = (l + r) >> 1;
if (check(mid)){
r = mid; // check()判断mid是否满足性质
}
else{
l = mid + 1;
}
}
return l;
}
3.代码(不带注释)
// 区间[l, r]被划分成[l, mid]和[mid + 1, r]时使用:
bool check(int x) {
}
int zs_erfen_2(int l, int r)
{
while (l < r){
int mid = (l + r) >> 1;
if (check(mid)){
r = mid;
}
else{
l = mid + 1;
}
}
return l;
}
浮点数二分
1.知识点
浮点数二分不需要考虑边界
2.步骤
1.确定eps 当两数差小到一定程度是则可认为找到数,一般为保留的小数位数多2
2.取中间值 double mid = (l + r) / 2
3.判断中间值是否满足左半边性质
if (check(mid)){
r = mid;
}
else{
l = mid;
}
4.直到边界范围小于eps即认为找到这个数
3.代码(带注释)
bool check(double x) {
} // 检查x是否满足右半边性质
double fds_erfen(double l, double r){ // 浮点数二分模板
//保留的小数位数多2
const double eps = 1e-6; // eps 表示精度,取决于题目对精度的要求
while (r - l > eps){ //当两数差小到一定程度是则可认为找到数
double mid = (l + r) / 2;
if (check(mid)){ //满足右半边性质,在左边
r = mid;
}
else{
l = mid;
}
}
return l;
}
4.代码(不带注释)
bool check(double x) {
}
double fds_erfen(double l, double r){
const double eps = 1e-6;
while (r - l > eps){
double mid = (l + r) / 2;
if (check(mid)){
r = mid;
}
else{
l = mid;
}
}
return l;
}

浙公网安备 33010602011771号