✌️作者:清水寺丞
☀️简介:正在学习算法,unity,数据库,计算机通信网络和python。喜欢部署各种奇奇怪怪的小项目。喜欢就点个关注一起学习吧~⛄️⛄️⛄️⛄️
目录
一、前言
作者在学习二分查找时,常常遇到对于二分查找的思想一学就会,真正写起来却困难重重的问题。每一次在写二分查找的代码时,常常弄不清是while(left<right)还是while(left<=right),也常常弄不清楚是left=mid+1还是left=mid。
于是写下这篇文章,来理清二分思想的思路,从思路上理解是while(left<right)还是while(left<=right);是left=mid+1还是left=mid。
二、二分查找
核心思想简述:
我们在算法运行过程中,每次更新中保证target的下标一定属于一个范围,然后我们不断缩小这个范围,当这个范围小到没有任何数在其中时,数组中没有这个数。
由于我们每次缩小范围都保证target的下标一定属于这个范围,故若数组中有这个数,在这个可能范围缩小到0的过程中,我们一定会发现target在这个范围的中央。
三、代码写法1
题目来自Leetcode
我们将在代码的思路简析与注释中了解如何具体确定target可能出现的下标范围。
代码思路简析:我们在算法运行过程中,每次更新中保证target的下标一定属于[left,right),然后我们不断缩小[left,right)这个范围。
当left=right或left<right,则范围[left,right)中不存在任何数,而我们在更新中保证了target一定处于[left,right)这个范围中,当[left,right)中不可能存在数时,target一定不存在于数组中。
注释版:
class Solution:
def search(self, nums: List[int], target: int) -> int:
n=len(nums)
#我们定义target可能的下标范围为[left,right)
#在算法中缩小范围时我们也要保证每一次更新后,
#target可能出现的下标范围仍然为[left,right)
#我们通过不断地缩小target可能出现的范围来找到target
#若target可能出现的下标范围已经小到没有数在其中
#则target不存在数组中
#一开始,target的下标可能存在范围为[0,n)
left=0
right=n
#因为target可能出现的下标范围为[left,right)
#故当left=right时,target已经不可能出现了
while(left<right):
#当前搜索范围的中心下标为int((left+right)/2)
mid=int((left+right)/2)
if(nums[mid]>target):
#如果中心的数大于target,由于升序,target的下标可能范围为[left,mid)
#故为了保证target属于[left,right),right=mid
right=mid
elif(nums[mid]<target):
#如果中心的数小于target,由于升序,target的下标可能范围为(mid,right)
#故为了保证target属于[left,right),left=mid+1
left=mid+1
else:
#若中心的数就是target,则返回中心下标
return mid
#当left<right
#target可能下标范围[left,right)缩小到其中没有一个数
return -1
纯净版代码:
class Solution:
def search(self, nums: List[int], target: int) -> int:
n=len(nums)
left=0
right=n
while(left<right):
mid=int((left+right)/2)
if(nums[mid]>target):
right=mid
elif(nums[mid]<target):
left=mid+1
else:
return mid
return -1
四、代码写法2 (left<=right):
这次我们保证target一定在[left,right]的范围内。
大家可以根据之前的逻辑自行练习。
class Solution:
def search(self, nums: List[int], target: int) -> int:
n=len(nums)
#target下标在[left,right]
left=0
right=n-1
#因为在[left,right]内,所以left=right时范围内仍然有下标存在
while(left<=right):
mid=int((left+right)/2)
if(nums[mid]<target):
#target属于(mid,right]
left=mid+1
elif(nums[mid]>target):
#target属于[left,mid)
right=mid-1
else:
return mid
return -1