一、概述
整数二分常用于解决寻找某些性质的边界的问题,性质往往是整数大小的范围
例如使用整数二分寻找下图所示的分界点1 和 分界点2:
整数二分大致分为三个步骤 :
1、由l==0 且 r==n-1确定区间中间点mid;
注意!mid有mid=l+r>>1 和 mid=l+r+1>>1两种确定方式
2、检查mid处的性质;
3、根据步骤2的结果相应地调整区间
例如寻找分界点1:
若mid处的性质为红色,则分界点1必定位于区间[mid,r]中,所以l=mid;
若mid处的性质为绿色,则分界点1必定位于区间[l,mid-1]中,所以r=mid-1
例如寻找分界点2:
若mid处的性质为绿色,则分界点2必定位于区间[l,mid]中,所以r=mid;
若mid处的性质为红色,则分界点2必定位于区间[mid+1,r]中,所以l=mid+1
二、题目
三、代码段
#include<iostream>
using namespace std;
const int N = 1e5+10;
int n,q,k;//长度为n、q次查询、查询k
int A[N];
int main()
{
cin>>n>>q;
for(int i=0;i<n;i++)
cin>>A[i];
while(q--)
{
cin>>k;
//核心代码块(1)
int l=0,r=n-1;
while(l<r)
{
int mid=l+r>>1;//步骤1、确定区间中间点mid
if(A[mid]>=k) //步骤2、检查mid处的性质
r=mid; //步骤3、根据步骤2的结果相应地调整区间
else
l=mid+1;
}
if(A[l]!=k) cout<<"-1 -1"<<endl;
//如果数组中不存在该元素,则返回 -1 -1
else
{
cout<<l<<" ";
//核心代码块(2)
l=0; r=n-1;
while(l<r)
{
int mid=l+r+1>>1;//步骤1、确定区间中间点mid
if(A[mid]<=k) //步骤2、检查mid处的性质
l=mid; //步骤3、根据步骤2的结果相应地调整区间
else
r=mid-1;
}
cout<<l<<endl;
}
}
return 0;
}
#include<iostream>
using namespace std;
const int N = 1e5+10;
int n,q,k;
int A[N];
int main()
{
cin>>n>>q;
for(int i=0;i<n;i++)
cin>>A[i];
while(q--)
{
cin>>k;
int l=0,r=n-1;
while(l<r)
{
int mid=l+r>>1;
if(A[mid]>=k) r=mid;
else l=mid+1;
}
if(A[l]!=k) cout<<"-1 -1"<<endl;
else
{
cout<<l<<" ";
l=0; r=n-1;
while(l<r)
{
int mid=l+r+1>>1;
if(A[mid]<=k) l=mid;
else r=mid-1;
}
cout<<l<<endl;
}
}
return 0;
}
//提取核心代码块
//核心代码块(1)
int l=0,r=n-1;
while(l<r)
{
int mid=l+r>>1;
if(A[mid]>=k) r=mid;
else l=mid+1;
}
//若r=mid,则l=mid+1 且 mid=l+r>>1
//对于至少包含一个整数且按照升序排列的整数数组A执行完核心代码块(1)后:
//1、l==r;
//2、若A中包含大于或等于k的元素,则A[l]==A[r]为A中第一个大于或等于k的元素;
//3、若A中只包含小于k的元素,则A[l]==A[r]==A[n-1]为A中最后一个元素
//核心代码块(2)
l=0; r=n-1;
while(l<r)
{
int mid=l+r+1>>1;
if(A[mid]<=k) l=mid;
else r=mid-1;
}
//若l=mid,则r=mid-1 且 mid=l+r+1>>1
//对于至少包含一个整数且按照升序排列的整数数组A执行完核心代码块(2)后:
//1、l==r;
//2、若A中包含小于或等于k的元素,则A[l]==A[r]为A中最后一个小于或等于k的元素;
//3、若A中只包含大于k的元素,则A[l]==A[r]==A[0]为A中第一个元素
推荐文章: 二分查找 - 整数