排除法二分查找

排除法二分查找

基础二分查找

以找到目标元素为目的进行查找,循环控制条件为while(left<=right),表示当left==right成立时,还要判断left(right)值和目标值的关系。
基础二分法将查找数组分成三部分:mid所在位置,mid左边位置和mid右边位置,如果nums[mid]==target,那么直接返回mid,否则根据条件改变搜索区间进行下一次搜索。
存在的问题:
目标值在数组中存在多个,但需要返回的是一个边界值,例如比小于等于target的第一个值等。

排除法二分查找

从哪些元素不是目标元素考虑。思路是:根据mid位置的元素,排除不可能存在目标元素的空间,下一轮在可能存在目标元素的区间中查找。
具体算法:
1.循环条件while(left<right)
循环过程中,left不断右移,right不断左移。退出循环的时候一定有left==right成立。注意:此时left(right)处的值可能还没有被读取,因此可能需要对left(right)处的值是否是目标元素的值做一次判断。
2.写ifelse语句时考虑nums[mid]为什么值时mid不是解,进而判断mid的左侧是否存在解,mid的右侧是否存在解。

两种边界收缩行为

1.mid被分到左边,即区间被分成[left, mid][mid+1, right]

if(check(mid)){
	//	下一轮检查的是[left, mid]
	right = mid;
}else{
	//	否则检查[mid+1, right]
	left = mid + 1;
}

2.mid被分到右边,即取键被分成[left, mid-1][mid, right]

if(check(mid){
	//	下一轮检查的是[left, mid-1]
	right = mid - 1;
}else{
	//	否则检查[mid, right]
	left = mid;
}

根据边界收缩行为修改中间数的行为

中间数的一般取法

int mid = (left + right) / 2;

如果left和right特别大可能发生整形溢出,改进的取法为:

int mid = left + (right - left) / 2;

这种写法几乎不会发生溢出。
注意/运算符是向下取整的,因此int mid = left + (right - left) / 2这种写法永远不会取到区间的最右侧元素。
在第二种边界收缩行为中,待搜索区间只有两个值时可能会发生死循环。
在这里插入图片描述
因此取中间数时根据两种边界收缩行为分成两种情况
1.mid分给左侧区间,[left, mid][mid+1, right],此时mid向下取整

int mid = left + (right - left) / 2;
if(check(mid){
   right = mid;
}else{
   left = mid + 1;
}

2.mid分给右侧区间,[left,mid-1][mid, right],此时mid向上取整

int mid = left + (right - left) / 2;
if(check(mid){
	right = mid - 1;
}else{
left = mid;
}

一种避免整形溢出的取中间数方法

int mid = (left + right) >>> 1;
>>>为无符号右移,使用这种方法可以避免整形溢出

排除二分法的两种模板

1.mid分给左侧区间[left, mid][mid+1, right]

while(left < right){
	int mid = (left + (right - left) / 2) >>> 1;
	if(check(mid)){
		right = mid;
	}else{
		left = mid + 1;
	}
}

2.mid分给右侧区间[left, mid - 1][mid, right]

while(left < right){
	int mid = (left + (right - left + 1) / 2) >>> 1;
	if(check(mid)){
		right = mid - 1;
	}else{
		left = mid;
	}
}

参考leetcode算法35题liweiwei1419大佬的解题,原文在这

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值