详解二分搜索,强攻细节问题

首先推荐一位业内大神 labuladong 看完大神的二分查找详解才算把二分搜索弄明白

二分搜索简单中的不简单,为什么这么说呢? 根据自身体会,细节处理不好过题全靠运气!
先来看一首小诗吧,帮助记忆。

                二级搜索升天词
                作者:labuladong
         二分搜索不好记,左右边界让人迷
         小于等于变小于, mid加一又减一
         就算这样还没完,return应否再减一
         信息慢慢刷力扣,AC比率二十一
         我本将心向明月,奈何明月照沟渠
         问君能有几多愁,恰似深情喂了狗
         
         labuladong从天降,一同手撕算法题
         赠军一法写二分,不用拜佛与念经
         管他左侧还右侧,搜索区间定乾坤
          
         搜索一个元素时,搜索区间两端闭
         while条件带等号,否则需要打补丁
         if相等就返回,其他的事甭担心
         mid必须加减一,因为区间两端闭
         while结束就凉了,凄凄惨惨返-1
         
         搜索左右边界是,搜索区间要阐明
         左闭右开最常见,其余逻辑便自明
         while要用小于号,这样才能不漏掉
         if相等别返回,利用mid锁边界
         mid加一或减一?要看区间开或闭
         while结束不算完,因为你还没返回
         索引可能出边界,if检查保平安
         
         左闭右开最常见,难道常见就合理?
         labuladong不信邪,偏要改成两端闭
         搜索区间记于心,或开或闭有何异
         二分搜索三变体,逻辑统一容易记
         一套框架改两行,胜过千言和万语
         
         此等神人何处寻?全靠缘分不可期
         labuladong公众号,开启算法新天地  

一、搜索一个数(最基本二分搜索)

int binarySearch(int nums[],int target){
	int left = 0, right = nums.length()-1;
	int mid = left+(right-left)/2;  // 与mid = (left + right)/2 效果相同,但是这样有效的避免了数组的越界问题;
	while(left <= right){
		if(nums[mid] == target) return mid;
		else if(nums[mid] > target) right = mid -1;
		else if (nums[mid] < target) left = mid + 1; 
	}
	return -1;
}
1、为什么是left <= right ?

举个栗子:在区间[2,2]中,left == right 则会跳出循环并不寻找nums[2]的值

2、为什么left = mid + 1,right = mid-1?

我们在[left,right]区间当中寻找target在left,right区间当中寻找的mid并没有对应target那应该在哪里寻找呢当然是在[left,mid-1]或者在[mid+1,right]当中。因为mid刚刚被搜索过因此不包括。

搜索左边界

int binary_left(int nums[],int target){
	int left = 0,right = nums.length();
	while(left < right){
		int mid = left + (right - left) / 2;
		if(nums[mid] == target) right = mid;
		else if (nums[mid] > target) left = mid+1;
		else if (nums[mid] < target) right = mid;  
	}
	return left;
}
1、为什么这次的条件改为了left < right

其实left <= right也完全可以,但是必须明确【搜索区间】的概念。这个条件下,while 终止的条件为 left == right 也就是搜索的区间为[left,right)区间,因为此时right的初始的设置为nums.length()而并非为nums.length()-1。

2、为什么right = mid而不是mid-1

根据上一个问题我们知道,查询到区间为[left,right)为左闭右开区间,我们并不对right进行查询,也就是mid已经查询过,在下一个区间当中,我们并不对mid进行查询,因此我们的right为mid。

3、为什么nums[mid] = target 时,right = mid

我们寻找的是左边界,因此我们对右边界是压缩的直到left = right

如果运用和搜索一个数相同的搜索区间如何写:

int binary_left(int nums[],int target){
	int left = 0, right = nums.length()-1;
	if(nums.length() == 0) return -1;
	while(left <= right){
	int mid = left + (right - left) / 2;
		if(nums[mid] == target) right = mid -1;
		else if (nums[mid] > target) right = mid -1;
		else if (nums[mid] < target) left = mid + 1;
	}
	/*检查出界的情况*/
	if(left > nums.length() || nums[left] != target) return -1;
	return left; 
}

三、搜索右边界

与搜索左边界是相同的道理,这里不多做赘述,直接上代码。

/*搜索的区间为左闭右开*/
int binary_right(int nums[],int target){
	int left = 0, right = nums.length();
	while(left < right){
		int mid = left + (right - left) / 2;
		if(nums[mid] == target)  left = mid + 1;
		else if (nums[mid] > target) left = mid -1;
		else if (nums[mid] < target) right = mid;
	}
	return left - 1;
}
1、为什么返回值为left-1

我们可以在脑中进行一次循环,当进行到最后一次循环时。这时的left = mid + 1 (可以看做mid = left -1) , nums[left] 的值肯定不等于target,mid是我们所需要的最后结果因此返回值为left-1

最后可以自己练习力扣的三道习题
278. 第一个错误的版本
35. 搜索插入位置
二分查找

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流云枫木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值