大家好,我是醉墨居士,今天聊一下计算机中的经典算法 - 二分算法
查找升序数组中某个数的索引
我们直接从头到尾遍历数组查找
判断当前数是否是要查询的数
如果是则直接返回索引
如果当前数大于要查询的数直接返回-1
如果不是则继续向后查找
如果最终也没找到,返回-1
def find_target(nums, target):
for i in range(len(nums)):
if nums[i] == target:
return i
if nums[i] > target:
return -1
return -1
遍历查找没有利用数组是升序的特点,而是简单的暴力搜索,无法进行有效的剪枝
时间复杂度O(N),空间复杂度O(1)
二分查找的核心就是利用数组是有序的特点
每次取待查找的区间的中点
如果中点对应的数等于要查找的数,直接返回中点索引
如果中点对应的数大于要查找的数,则在待查找的区间的左半区域进行查找
如果中点对应的数小于要查找的数,则在待查找的区间的右半区域进行查找
如果最终也没找到,返回-1
def binary_find(nums, target):
low, high = 0, len(nums) - 1
while low <= high:
mid = (low + high) >> 1
if nums[mid] == target:
return mid
elif nums[mid] > target:
high = mid - 1
elif nums[mid] < target:
low = mid + 1
return -1
合理利用有序数组这个特点,进行剪枝,每次查找都会减少一半的查询范围
时间复杂度O(Log N),空间复杂度O(1)
查找大于等于某个数最左边的数的索引,例如:[0,1,2,2,3,6,7] 中查找2的索引是2
每次取待查找的区间的中点
如果中点对应的数大于等于要查找的数,则更新结果,并在待查找的区间的左半区域进行查找
如果中点对应的数小于要查找的数,则在待查找的区间的右半区域进行查找
如果最终也没找到,返回结果
def find_left(nums, target):
low, high = 0, len(nums) - 1
ans = -1
while low <= high:
mid = (low + high) >> 1
if nums[mid] >= target:
ans = mid
high = mid - 1
else:
low = mid + 1
return ans
查找旋转数组的最小值,例如:[4,5,6,7,0,1,2] 中的最小值为 0
每次取待查找的区间的中点
如果中点对应的数大于右边界对应的数,则在待查找的区间的右半区域进行查找
如果中点对应的数小于等于右边界对应的数,则在待查找的区间的左半区域进行查找
直到最终查询完毕,返回左端点对应的数
def find_min(nums):
low, high = 0, len(nums) - 1
while low < high:
mid = (low + high) >> 1
if nums[mid] > nums[high]:
low = mid + 1
else:
high = mid
return nums[low]