二分查找
适合场景
- 二分查找依赖的是顺序表结构,简单点说就是数组
- 二分查找针对的是有序数据。
- 数据量太小不适合二分查找。
- 数据量太大也不适合二分查找。
写二分算法的注意点
- 循环退出条件
- mid 的取值(防止溢出)
- low 和 high 的更新
程序
循环写法
from typing import List
# 循环写法
def binary_search(nums: List[int], target: int) -> int:
"""
nums:一个数字列表
target:目标值
return:目标值在列表中的索引,
"""
if len(nums) == 0:
return -1
low = 0
high = len(nums)-1
while low<=high: # 小于等于
mid = low + ((high-low) >> 1) # 取整,移位更高效,防止溢出
if nums[mid] == target:
return mid
elif nums[mid] > target:
high = mid-1 #
elif nums[mid] < target:
low = mid+1 #
return -1
递归写法
from typing import List
# 循环写法
def binary_search(nums: List[int],low: int, high: int, target: int) -> int:
if low > high:
return -1
mid = low + ((high-low) >> 1) # 取整,移位更高效,防止溢出
if nums[mid] == target:
return mid
elif nums[mid] > target:
return binary_search(nums, low, mid-1, target)
elif nums[mid] < target:
return binary_search(nums, mid+1, high, target)
二分查找的变形
查找第一个值等于给定值的元素
如果 mid 等于 0,那这个元素已经是数组的第一个元素,那它肯定是我们要找的;如果 mid 不等于 0,但 a [mid] 的前一个元素 a [mid-1] 不等于 value,那也说明 a [mid] 就是我们要找的第一个值等于给定值的元素。
from typing import List
# 循环写法
def binary_search(nums: List[int], target: int) -> int:
if len(nums) == 0:
return -1
low = 0
high = len(nums)-1
while low<=high: # 小于等于
mid = low + ((high-low) >> 1) # 取整,移位更高效,防止溢出
if nums[mid] > target:
high = mid-1 #
elif nums[mid] < target:
low = mid+1 #
else:
if (mid==0) or (nums[mid-1] != target):
# mid-1 代表往前找,mid=0 说明已经是第一个元素了
return mid
else:
high = mid - 1
return -1
往前一直找
from typing import List
# 循环写法
def binary_search(nums: List[int], target: int) -> int:
if len(nums) == 0:
return -1
low = 0
high = len(nums)-1
while low<=high: # 小于等于
mid = low + ((high-low) >> 1) # 取整,移位更高效,防止溢出
# print(mid)
if nums[mid] == target:
while nums[mid-1] == target:
mid -= 1
return mid
elif nums[mid] > target:
high = mid-1 #
elif nums[mid] < target:
low = mid+1 #
return -1
查找最后一个值等于给定值的元素
from typing import List
# 循环写法
def binary_search(nums: List[int], target: int) -> int:
if len(nums) == 0:
return -1
low = 0
high = len(nums)-1
while low<=high: # 小于等于
mid = low + ((high-low) >> 1) # 取整,移位更高效,防止溢出
if nums[mid] > target:
high = mid-1 #
elif nums[mid] < target:
low = mid+1 #
else:
# mid+1 代表往后找,mid=len(nums)-1 说明已经是最后一个元素了
if (mid==len(nums)-1) or (nums[mid+1] != target):
return mid
else:
low = mid + 1
return -1
往后面去找
from typing import List
# 循环写法
def binary_search(nums: List[int], target: int) -> int:
if len(nums) == 0:
return -1
low = 0
high = len(nums)-1
while low<=high: # 小于等于
mid = low + ((high-low) >> 1) # 取整,移位更高效,防止溢出
# print(mid)
if nums[mid] == target:
while nums[mid+1] == target:
mid += 1
return mid
elif nums[mid] > target:
high = mid-1 #
elif nums[mid] < target:
low = mid+1 #
return -1
查找第一个大于等于给定值的元素
from typing import List
# 循环写法
def binary_search(nums: List[int], target: int) -> int:
if len(nums) == 0:
return -1
low = 0
high = len(nums)-1
while low<=high: # 小于等于
mid = low + ((high-low) >> 1) # 取整,移位更高效,防止溢出
if nums[mid] >= target:
if ((mid == 0) or (nums[mid - 1] < target)):
return mid;
else:
high = mid - 1
elif nums[mid] < target:
low = mid+1 #
return -1
查找最后一个小于等于给定值的元素
from typing import List
# 循环写法
def binary_search(nums: List[int], target: int) -> int:
if len(nums) == 0:
return -1
low = 0
high = len(nums)-1
while low<=high: # 小于等于
mid = low + ((high-low) >> 1) # 取整,移位更高效,防止溢出
if nums[mid] > target:
high = mid - 1
else:
if (mid==len(nums)-1) or nums[mid+1] > target:
return mid
else:
low = mid+1 #
return -1