文章目录
二分法——区间与选择
常见区间分类
1.左闭右闭
左闭右闭区间——[L,R];
while (l <= r) {
int mid = l + (r - l) / 2;
if (a[mid] > x) {
r = mid - 1;
}
else if (a[mid] < x) {
l = mid + 1;
}
else {
l = mid;
break;
}
}
因为区间的两个端点都是可以取到的,所以while循环中,l==r是合法的,即存在[1,1]这种合法情况,if判断语句中,一定要把a[mid] == x和<或>关系分开来写,因为a[mid]>=x;表示——>a[mid]>x <mark>或</mark>a[mid]==x,因为端点r或者l是包括在区间内部的,所以当a[mid]>x时,r不能等于mid,因为mid处的值已经被判断为了比x大,应该将mid排除在区间外,但是如果a[mid]= =x同时与a[mid]>x同时存在时,r若不等于mid(即r= =mid-1),那么就直接将a[mid]= =x这种mid的情况排除在了区间外,这样子无法得到正确的结果,所以a[mid]>x与a[mid]= =x分开来判断。
2.左闭右开
左闭右开区间——[L,R);
while (l < r) {
int min = l + (r - l) / 2;
if (a[mid]>=x) {
r = mid;
}
else {
l = mid + 1;
}
}
区间的左端点l包括在区间内,而右端点r不包括在区间内,故l不能等于r,即[1,1)——1既存在在区间内,又不存在在区间内,这种区间是不合法的,由此,while循环判断条件l不能等于r。当a[mid]>=x时,为什么mid可以赋值给了r呢?——>因为,r不属于区间内,所以r= =mid时,新的区间内并不包含mid,但是这样的不包含,不影响对于a[mid]= =x的情况的后续操作,因为r依旧指向x元素,在接下来的二分中,r始终指向x元素,而l在不断向x元素逼近,最终,当l= =r的时候,就找到了x的位置。l=mid+1;——>当a[mid]<x的时候,x一定位于不包含mid位置的右区间里面,而[L,R),区间更新后,l始终位于区间内部,所以若l= mid,那么就把已经判断过不属于新区间的值又包含在区间内了,故r=mid+1;将mid位置排除在区间外面。
3.实数二分区间
实数二分区间不需要区间判断,需要考虑的是精度的问题
while ((r - l) > eps) {
double mid = l + (r - l) / 2;
if (check(mid))
l = mid;
else
r = mid;
}
l,r直接用mid来赋值就可以了。