二分查找算法是一种常用的查找算法,也被称为折半查找算法。它适用于有序数组的查找,并通过将待查找区间不断缩小一半的方式来快速定位目标值。
算法思想如下:
二分查找算法的时间复杂度为 O ( log n ) O(\log n) O(logn) ,其中 n n n 为数组的大小。由于每次查找都将待查找区间缩小一半,因此它比线性查找算法更加高效。
区间开闭问题
m i d mid mid 取值问题
常见的两种取值公式
mid = (left + right) // 2 # 使用较多
mid = (left + right + 1) // 2
mid = (left + right) // 2
能取到中间靠左边元素的下标位置。mid = (left + right + 1) // 2
能取到中间靠右边元素的下标位置。出界条件的判断
两种判断方式
left <= right
left < right
left <= right
,并且查找的元素不在有序数组中,则 while
语句的出界条件是 left > right
,也就是 left == right + 1
,写成区间形式就是 [ r i g h t + 1 right+1 right+1, r i g h t right right],此时待查找区间为空,待查找区间中没有元素存在,此时终止循环时,可以直接返回 −1。left < right
,并且查找的元素不在有序数组中,则 while
语句出界条件是 left == right
,写成区间形式就是 [ r i g h t right right, r i g h t right right]。此时区间不为空,待查找区间还有一个元素存在,我们并不能确定查找的元素不在这个区间中,此时终止循环时,如果直接返回 −1 就是错误的。使用 left < right
的话,可以在出界之后增加一层判断,判断是否等于目标元素。
# ...
while left < right:
# ...
return left if nums[left] == target else -1
此时,在跳出循环的时候,一定是 left == right
,无需判断此时应该返回 left or right
搜索区间范围的选择
三种写法
left = mid + 1,right = mid - 1
left = mid + 1 ,right = mid
left = mid,right = mid - 1
具体哪一种写法和二分查找的两种思路有关。
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
# 在区间 [left, right] 内查找 target
while left <= right:
# 取区间中间节点
mid = left + (right - left) // 2
# 如果找到目标值,则直接范围中心位置
if nums[mid] == target:
return mid
# 如果 nums[mid] 小于目标值,则在 [mid + 1, right] 中继续搜索
elif nums[mid] < target:
left = mid + 1
# 如果 nums[mid] 大于目标值,则在 [left, mid - 1] 中继续搜索
else:
right = mid - 1
# 未搜索到元素,返回 -1
return -1
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
# 在区间 [left, right] 内查找 target
while left < right:
# 取区间中间节点
mid = left + (right - left) // 2
# nums[mid] 小于目标值,排除掉不可能区间 [left, mid],在 [mid + 1, right] 中继续搜索
if nums[mid] < target:
left = mid + 1
# nums[mid] 大于等于目标值,目标元素可能在 [left, mid] 中,在 [left, mid] 中继续搜索
else:
right = mid
# 判断区间剩余元素是否为目标元素,不是则返回 -1
return left if nums[left] == target else -1
704. 二分查找
思路
-1
代码
class Solution:
def search(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1 # 设定左右边界
while left <= right:
mid = (left + right) // 2 # 取中间节点
if nums[mid] == target: # 中间节点值等于目标值,返回中间位置
return mid
elif nums[mid] > target: # 中间节点值大于目标值,区间换成[left, mid-1]
right = mid - 1
else:
left = mid + 1 # 中间节点值小于目标值,区间换成[mid+1, right]
return -1
35. 搜索插入位置
思路
代码
class Solution:
def searchInsert(self, nums: List[int], target: int) -> int:
left, right = 0, len(nums) - 1
while left <= right:
mid = (left + right) // 2
if nums[mid] == target:
return mid
elif nums[mid] > target:
right = mid - 1
else:
left = mid + 1
return left # 目标值不存在,直接返回左端下标值
374. 猜数字大小
思路
代码
# The guess API is already defined for you.
# @param num, your guess
# @return -1 if num is higher than the picked number
# 1 if num is lower than the picked number
# otherwise return 0
# def guess(num: int) -> int:
class Solution:
def guessNumber(self, n: int) -> int:
left, right = 1, n
while left <= right:
mid = (left + right) // 2
result = guess(mid)
if result == 0:
return mid
elif result == -1:
right = mid - 1
else:
left = mid + 1
69. x 的平方根
思路
代码
class Solution:
def mySqrt(self, x: int) -> int:
left, right, res = 0, x, -1
if x == 0 or x == 1:
return x
while left <= right:
mid = (left + right) // 2
if mid * mid <= x:
res = mid
left = mid + 1
else:
right = mid - 1
return res
参考文献
—— END ——
如果以上内容有任何错误或者不准确的地方,欢迎在下面 留言。或者你有更好的想法,欢迎一起交流学习~~~
更多精彩内容请前往 AXYZdong的博客