代码随想录算法训练营第一天| 704. 二分查找 详细分析

代码随想录算法训练营第一天| 704. 二分查找

ctrl老师文章链接
:https://programmercarl.com/0704.%E4%BA%8C%E5%88%86%E6%9F%A5%E6%89%BE.html
视频讲解:https://www.bilibili.com/video/BV1fA4y1o715
704. Binary Search
在这里插入图片描述
说到二分搜索一提起来大家都觉得很简单,就是就是不断地随小范围,最终随缩小到只剩一个或者恰好端点就是要找的提前结束,大部分人心里都有个框架,但是二分搜索却又没有这么简单,这里由两个问题一个是while(left right)到底是小于还是小于等于,另一个是right = middle呢,还是right = middle -1。我在学习二分搜索的时候完全是在乱写,完全不知道该依据什么来写,如果ac救过,报错看眼答案是小于等于就改成小于等于,并没有意识到这两个问题是配套的,稀里糊涂就过去了,看了卡尔老师讲解才明白,之所以不明白条件该如何写是因为区间没有想明白,每次循环要保证区间定义是不变的,区间定义决定了条件设置,比如left小于等于right说明right在区间内,那么我们采用的区间其实就是左闭右闭,如果left小于right,说明right不在区间内,那么说明是左闭右开
我们这里使用两种区间定义的方法,左闭右闭即[left, right],或者左闭右开即[left, right)。首先确定你要选择的区间定义,然后根据区间决定两个边界条件如何设置

  1. 左闭右闭
    此时循环条件应为left<=right,因为当left=right,应该被包含在[left, right]区间内,因此while条件应带有等于这种情况
    当middle= left+(right-left)//2
    那么当我们发现target在mid的左面,那么right需要更新,此时因为target和mid处的值不相等,说明下一个搜索的范围不应该含有middle这个位置,区间范围是左闭右闭,那么区间的两个端点都应该在搜索范围,也就是说区间的所有点都有可能等于target。因为已经明确知道了middle这个点与target不相等,应该从middle-1开始搜索,因此right=middle-1。当target在middle的右面,说明left需要更新,同理明确知道middle不等于target,不应该在左闭右闭的范围中,那么left=middle+1
    注意如果middle=(left+right)/2有时候相加会越界,为了避免这种情况,我们使用left+(right-left)//2确保不会出问题
    那么大家可能会有疑惑,middle也就比middle-1多了一个点,也就浪费一点时间,无所谓。那就问题大了,区间的定义发生了改变,如果不对middle做任何处理,当想找的点不在数组中会造成死循环。,
  2. 左闭右开
    此时循环条件为left<right,因为当left=right不被包含在[left, right)区间中,
    那么当target在middle的左面,那么right需要更新,,并且需要去左区间继续寻找,而寻找区间是左闭右开区间, right不在区间内,我们目前知道middle不等于target,因此middle不在区间内,但是middle-1是否在区间不清楚,那么假如让right=middle-1,如果middle-1在区间内,而right却不在区间,则把middle-1忽略了,因此就让right=middle就可以了,那么当target在middle的右面,需要更新left,但是左闭右开区间,left在区间内,因此left要等于middle+1,如左闭右闭道理一样。还有个十分容易被忽略的就是right的初始化,因为right是开区间,所以right如果取len(给定数组)-1,那么此时right是在区间内的,而len(给定数组)不在区间内,所以应该取后者
1.	class Solution:  
2.	    def search(self, nums: List[int], target: int) -> int:  
3.	        #[left,right)  
4.	        left,right=0,len(nums)  
5.	        while left<right:  
6.	            mid=left+(right-left)//2  
7.	            if nums[mid]<target:  
8.	                left=mid+1  
9.	            elif nums[mid]>target:  
10.	                right=mid  
11.	            else:  
12.	                return mid  
13.	        return -1  
14.	      
15.	        #[left,right]  
16.	        left,right=0,len(nums)-1  
17.	        while left<=right:  
18.	            mid=left+(right-left)//2  
19.	            if nums[mid]<target:  
20.	                left=mid+1  
21.	            elif nums[mid]>target:  
22.	                right=mid-1  
23.	            else:  
24.	                return mid  
25.	        return -1  
26.	        # return -1 


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值