二分查找模板小结(三种:第一种基础,推荐掌握第二种,第三种是第二种的变体)
刷题要总结,以块进行刷题。还有参加周赛,哪里不会学哪块。一个是积累基础,一个是查漏补缺。加油
以力扣704题为例:
题目描述:
题解:
方法1: 循环条件为left <= right。先看mid处的值与target的关系,如果相等就输出,然后划分为两个区间[left,mid -1],[mid +1,right]
class Solution:
def search(self, nums: List[int], target: int) -> int:
#模板一:
if nums == []:#特例判断
return -1
n = len(nums)
left,right = 0,n-1
while left <= right:
mid = left +(right - left) // 2 #中间处下标,向下取整
if nums[mid] == target:
return mid
elif nums[mid] > target:#[left,mid -1]
right = mid - 1
else: #[mid +1,right]
left = mid + 1
return -1
方法2: 推荐掌握,循环条件为left < right,循环结束时一定有left = right,最后需要判断nums[left]与target的关系。此有两个版本:(1)mid向下取整,则区间分为[left,mid],[mid+1,right](2)mid向上取整,则区间分为[left,mid-1],[mid,right]
(1)mid向下取整(寻找左端点)
则区间分为[left,mid],[mid+1,right]
class Solution:
def search(self, nums: List[int], target: int) -> int:
#模板二:向下取整,
if nums == []:
return -1
n = len(nums)
left,right = 0,n
while left < right:
mid = left + (right - left) // 2#中间处下标,向下取整
if nums[mid] >= target:#[left,mid]
right = mid
else: #[mid+1,right]
left = mid + 1
return left if nums[left] == target else -1
或者:
class Solution:
def search(self, nums: List[int], target: int) -> int:
#模板二:向下取整,
if nums == []:
return -1
n = len(nums)
left,right = 0,n - 1
while left < right:
mid = (left + right) >> 1 #中间处下标,向下取整
if nums[mid] >= target:#[left,mid]
right = mid
else: #[mid+1,right]
left = mid + 1
return left if nums[left] == target else -1
(2)mid向上取整(寻找右端点)
则区间分为[left,mid-1],[mid,right]
class Solution:
def search(self, nums: List[int], target: int) -> int:
#模板二:向上取整
if nums == []:
return -1
n = len(nums)
left,right = 0,n
while left < right:
mid = left + (right - left +1) // 2#中间处下标,向上取整
if nums[mid] <= target:#[mid,right]
left = mid
else: #[left,mid-1]
right = mid - 1
return right if nums[right] == target else -1
或者:
class Solution:
def search(self, nums: List[int], target: int) -> int:
#模板二:向上取整
if nums == []:
return -1
n = len(nums)
left,right = 0,n - 1
while left < right:
mid = (left + right + 1) >> 1 #中间处下标,向上取整
if nums[mid] <= target:#[mid,right]
left = mid
else: #[left,mid-1]
right = mid - 1
return right if nums[right] == target else -1
方法3:循环条件为left + 1 <right,在循环体中,先判断nums[mid]
和target的大小,相等返回;不相等,返回[left,mid],[mid,right]。最后循环结束时还要再次判断left、right处的值与target是否相等。
class Solution:
def search(self, nums: List[int], target: int) -> int:
#模板三:
if nums == []:
return -1
left ,right = 0,len(nums) -1
while left +1 < right:
mid = left + (right - left) // 2#向下取整
if nums[mid] == target:
return mid
elif nums[mid] > target: #[left,mid]
right = mid
else: #[mid,right]
left = mid
if nums[left] == target:
return left
if nums[right] ==target:
return right
return -1
附上:
1、寻找左端点:
class Solution:
def search(self, nums: List[int], target: int) -> int:
#找左端点
left,right = 0,len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
elif nums[mid] == target:
right = mid - 1
return left if nums[left] == target else -1
2、寻找右端点:
class Solution:
def search(self, nums: List[int], target: int) -> int:
#找右端点
left,right = 0,len(nums) - 1
while left <= right:
mid = left + (right - left) // 2
if nums[mid] < target:
left = mid + 1
elif nums[mid] > target:
right = mid - 1
elif nums[mid] == target:
left = mid + 1
return right if nums[right] == target else -1
复杂度分析
三种方法的时间复杂度都为O(logN)
空间复杂度都为O(1)