整数的二分查找
整数的二分查找是比较麻烦的,因为计算mid值时用到除法,会向下取整,因而界定范围就变得很困难。
根据y总的两个模板:
while(l<r)
{
int mid=(l+r)/2;
if(a[mid]>=t) r=mid;
else l=mid+1;
}
while(l<r)
{
int mid=(l+r+1)/2;
if(a[mid]<=t) l=mid;
else r=mid-1;
}
这两个模板可根据实际情况来用,根据所求数据与mid的大小,从而调整左右边界。
1.当a[mid]>=t时,t是要查找的数据,如图:
while(l<r)
{
int mid=(l+r)/2;
if(a[mid]>=t) r=mid;
else l=mid+1;
}
此时,我们需要更新右边界,又因为是>=,所以可以令r=mid,而不是r=mid-1。
而如果不满足条件,我们则需要更新左边界,因为不满足时条件时为a[mid]<t;
a[mid]无法被取到,所以左边界l不能等于a[mid]这一点,故写成l=mid+1。
2.当a[mid]<=t时,如图:
while(l<r)
{
int mid=(l+r+1)/2;
if(a[mid]<=t) l=mid;
else r=mid-1;
}
此时,我们需要更新左边界,又因为是<=,所以可以令l=mid,而不是l=mid+1。
而如果不满足条件,我们则需要更新右边界,因为不满足时条件时为a[mid]>t;
a[mid]无法被取到,所以右边界r不能等于a[mid]这一点,故写成r=mid-1。
为什么求mid时要在这里加1呢?
int mid=(l+r+1)/2;
我们不妨设只有两个数a[0]=2和a[1]=3,要求的t为a[1]的值。
那么当我们求mid时,(l+r)/2这个式子,(0+1)/2由于计算结果为浮点数,便向下取整,这便使得mid仍为0。
a[mid]=a[0]<a[1],满足循环条件a[mid]<=t。
if(a[mid]<=t) l=mid;
那么,更新后的左边界l仍为0,就此陷入死循环。所以在此+1是为了避免死循环的出现。
while(l<r)
{
int mid=(l+r)/2;
if(a[mid]>=t) r=mid;
else l=mid+1;
}
while(l<r)
{
int mid=(l+r+1)/2;
if(a[mid]<=t) l=mid;
else r=mid-1;
}
根据情况选择模板使用,这个模板二分后必定有解。
也就是必定会找到一个数。
但这个找到的数的值与题目需要的值是否相等便需要进一步判断了。
2022/11/4 23:58