• 搜索
  • 关于二分搜索(答案)三种写法的分析

  • @ 2025-6-1 15:21:09

二分法的前提是:有序序列或者答案值区间是有序的

二分查找的写法按照区间设置的不同有三种写法,它们最大的不同点是每次缩小范围的时候L或R的赋值不同,以及最后答案所在位置不同。

一、1型,区间为一闭一开(L,R]或[L,R):

代码标志行:while(R-L>1)

(1)【1型】最大值最小类型的前开后闭区间写法:

//求最大值最小,前开后闭区间(L,R]
	int L,R,M;
	L=amin-1,R=amax+1;//答案区间范围(L,R],L是答案的下限-1,R是答案的上限+1;
	//注意区间范围宁可过大,也不要过小
	//L是开区间所以需要-1,R虽然是闭区间但是为了验证找不到答案的情况范围也需要扩大1
	while(R-L>1){//只要(L,R]区间超过1个数,继续二分查找 
		M=L+(R-L)/2;//二分,等价于=(r+l)/2,这样写防止r+l爆int范围 
		if(check(M)){//如果M是可行的答案 
			//ans=M;//可不写 
			R=M;//缩小R,由于(L,R],R表示可能是答案,所以这里不需要M-1 
		}else{//否则M不是答案 
			L=M;//缩小L,由于(L,R],L本身不是答案,所以不需要M+1; 
		}
	}
	if(R!=amax+1)//最后只要R有移动过,那么找到答案 
		cout<<R;//最后停止在区间(L,R]即(ans-1,ans]; 
	else//如果R未移动过,就是答案不在(L,R]范围内 
		cout<<"No answer";//最后停止在区间(amax,amax+1]; 
	//这种写法答案可以为:L+1==R==ans
	

(2)【1型】最小值最大类型的前闭后开区间写法:

	//求最小值最大,前闭后开区间[L,R) 
	int L,R,M;
	L=amin-1,R=amax+1;
	while(R-L>1){//[)
		M=L+(R-L)/2;
		if(check(M)){
			//ans=M;//可不写 
			L=M;
		}else{
			R=M;
		}
	}
	if(L!=amin-1)
		cout<<L;//[L,R)即[ans,ans+1)
	else
		cout<<"No answer";
	//这种写法答案可以为:L==R-1==ans

2、0型,区间为闭合区间[L,R]

代码标志行:while(L<R) //while(R-L>0)

(1)【0型】最大值最小类型的前闭后闭区间写法:

//求最大值最小,前闭后闭区间[L,R]
	int L,R,M,ans;
	L=amin,R=amax+1;
	while(L<R){//[],即 R-L>0
		M=L+(R-L)/2;
		if(check(M)){
			ans=m;//可不写 
			R=M;
		}else{
			L=M+1;
		}
	}
	if(R!=amax+1)
		cout<<R;//[L,R],L==R==ans
	else
		cout<<"No answer";	
	//这种写法答案可以为:L==R==ans

(2)【0型】最小值最大类型的前闭后闭区间写法:

	//求最小值最大,前闭后闭区间[L,R] 
	int L,R,M,ans;
	L=amin-1,R=amax;
	while(L<R){//[],即 R-L>0
		M=L+(R-L)/2+1;//注意这里M=(L+R)/2+1; 否则while死循环
		if(check(M)){
			ans=m;//可不写 
			L=M;
		}else{
			R=M-1;
		}
	}
	if(L!=amin-1)
		cout<<L;//[L,R],L==R==ans
	else
		cout<<"No answer";
	//这种写法答案可以为:L==R==ans

3、-1型,区间为闭合区间[L,R]

代码标志行:while(L<=R) //while(R-L>-1)

(1)【-1型】最大值最小类型的前闭后闭区间写法:

	//求最大值最小,前闭后闭区间[L,R]
	int L,R,M,ans;
	L=amin,R=amax+1;
	while(L<=R){//][,即 R-L>-1 或 R-L>=0 
		M=L+(R-L)/2;
		if(check(M)){
			ans=m;//可不写,但是一般会用ans定位答案 
			R=M-1;
		}else{
			L=M+1;
		}
	}
	if(R!=amax+1)
		cout<<ans;//[R,L],L和R错位 ],[ 。
	else
		cout<<"No answer";		
	//这种写法答案可以为:ans==L==R+1

(2)【-1型】最小值最大类型的前闭后闭区间写法:

	//求最小值最大,前闭后闭区间[L,R] 
	int L,R,M,ans;
	L=amin-1,R=amax;
	while(L<=R){//][,即 R-L>-1 或 R-L>=0 
		M=L+(R-L)/2;//注意这里M不需要+1,因为L=M+1不会造成while死循环
		if(check(M)){
			ans=m;//可不写,但是一般会用ans定位答案
			L=M+1;
		}else{
			R=M-1;
		}
	}
	if(L!=amin-1)
		cout<<ans;//[R,L],L和R错位 ],[ 
	else
		cout<<"No answer";
	//这种写法答案可以为:ans==R==L-1

以上三种写法“1型”代码最简单,所以推荐使用“1型”,但是大部分初赛题目,都会出代码较复杂的“0型”和“-1型”,所以上述三种写法都要掌握。

只要掌握了老师讲的坐标轴区间画法,那么三种写法都能轻松搞定。

另外关于区间L,R的初始值设定宁可超过,不可不够

如果无法分析范围区间的时候,可以直接设置为题目给的数据范围的最大范围区间即可

0 条评论

目前还没有评论...