二分查找入门攻略

Posted 小猫咪吃python

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了二分查找入门攻略相关的知识,希望对你有一定的参考价值。

承接上篇文章


二分又叫折半。用于在有序序列中搜索指定目标。每次都根据目标在完整区间的可能位置,将区间分成左右两半,这样每次搜索都会缩小搜索区域到一半,所以具有O(logn)的时间复杂度。


如果实现呢?

实现一般分为循环和递归两种模式,我们主要使用循环的模式。下面二分查找的实现代码分成三个部分。

  1. 确定需要搜索的目标。

  2. 确定比较条件。

  3. 选择下次搜索的区间。

下面处理一些例题来明确上面三步的具体含义。



题目简介

存在重复元素的有序数组里查找给出的目标值的第一个和最后一个位置。


使用上面的方法来完成

  1.  确定需要搜索的目标。因为这题有两个需要搜索的目标,所以要二分两次先找第一个目标,也就是target第一次出现的位置。

  2. 确定比较条件。我们把数组的首尾分别设为left和right,把数组的中间设置为mid。我们将比较条件设置为target>mid(如果设置其它条件后面选择区间时候也要做出相应改变。)。

  3. 选择下次搜索的区间。目前为止,mid将整个区间分为左右两个区间。当比较条件成立的时候这意味着要搜索的值严格比mid更大,所以target应该在右面的区间,并且不包括mid。所以当条件成立时我们下次搜索区间是[mid + 1, r],即把左指针移动到mid+1;如果比较条件不成立,这意味着target此时小于等于mid,所以我们下次搜索区间就是[l, mid],即右指针移动到mid。(这里可以想一下为什么这样能搜索到第一个target?因为我们的条件是target严格大于mid,这样在搜索到的mid等于target的元素时候就能移动右指针,从而结束循环)


  4. 上面的操作每次都会将寻找的区间缩小一半,又因为左指针是从左扫描,而右指针从右扫描,所以左指针应该一直小于右指针。所以设置循环条件为left小于right。这样最后结束的时候两个指针会指向同一个位置。

while l < r:    mid = (l + r) // 2 if target > nums[mid]: l = mid + 1 else: r = mid

这样我们就找到了target的第一个出现的位置。再用同样的方法找到target最后一个出现的位置。

  1. 确定需要搜索的目标,target最后出现的位置。

  2. 确定比较条件。因为要确定最后一个位置,所以我们让比较条件为target>=mid。这样才能在遇到相等元素时才能继续移动左指针找到最后一个target元素。

  3. 选择下次搜索的区间。如果比较条件成立,说明下次搜索的区间在[mid, right],即左指针移动到mid。如果条件不成立,说明target应该严格小于mid,这时候搜索[left, mid - 1]。

l, r = 0, len(nums) - 1while l < r: mid = (l + r + 1) // 2 if target >= nums[mid]: l = mid else: r = mid - 1

tips:这里有个两个小技巧

  1.  确定mid时候,如果下一个搜索区间里用了left = mid,则mid=(l+r+1)//2;这样做可以防止当l=0,r=1的时候算出来的mid是0,然后l=0,无限循环下去;反之,如果下一个区间里用了left = mid + 1,则mid = (l+r)//2。

  2. 确定下次搜索区间的关键就在于哪个区间里可以选择mid。第一个二分里用了target>mid(target<=mid),则target小于等于mid成立时候,可以选到mid;第二个二分里target>=mid成立,则在搜索右区间的时候可以选到mid。


完整代码

 def searchRange(self, nums: List[int], target: int) -> List[int]: if not nums: return [-1, -1] res = [-1, -1] l, r = 0, len(nums) - 1 while l < r: mid = l + r >> 1 if target > nums[mid]: l = mid + 1 else: r = mid print(r) res[0] = r if nums[r] == target else -1 l, r = 0, len(nums) - 1 while l < r: mid = l + r + 1 >> 1 if target >= nums[mid]: l = mid else: r = mid - 1 res[1] = r if nums[r] == target else -1 return res if -1 not in res else [-1, -1]


以上是关于二分查找入门攻略的主要内容,如果未能解决你的问题,请参考以下文章

VSCode插件开发全攻略代码片段设置自定义欢迎页

⭐算法入门⭐《二分枚举》中等02 —— LeetCode 面试题 10.09. 排序矩阵查找

入门算法-二分查找,二分排序,插入排序,冒泡排序

算法入门 02二分查找(简单 - 第四题)LeetCode 167

新手入门篇-二分查找局部最小链表问题

14天算法入门-第1天-二分查找