所谓二分查找,就是在一个有序数组(列表)中,通过数组中间值的下标将数组左(left)右(right)分开成两个数组,如果中间值比要查找的元素小,则要查找的元素自然应该在通过该中间值分开的数组的右边,那么此举就将原来的数组缩小到了该中间值的右边的数组了,再将缩小范围后的新数组继续上面的步骤,直到数组被缩小查找到值或返回False,反之则是左边继续重复上面的步骤,如果中间值等于要查找的元素则直接返回其中间值下标即可。
举例:注意此二分查找的是有序数组
查找 元素target:5 在列表lst = [1,2,3,4,5,6,7,8,9,10]的下标位置
思路:
最开始left的下标是0,对应元素是1,而最后面(右侧)right对应的下标则是列表长度-1,即right=len(lst) - 1
而中间值应该是长度除以2嘛,注意有时候长度并不一定是一个偶数(而恰恰奇数反而是可以取到中间值的),所以为了能够取到中间值对应的下标,我们使用mid = (right - left) // 2 + left 的形式,通过地板除保证能够取到整数值move_num(该值保证了一个数组取一半的长度),而+ left是为了从数组最左边开始移动move_num个单位取到该中间值对应的下标。
然后通过中间值和下标left,right对应的值进行比较来判断数组应该是十分之后取左边再继续十分还是取右边再继续二分。直到left,right相等取出返回查找值的下标或者返回不存在。
时间复杂度:O(log n) 其中n是数组的长度
空间复杂度:O(1)
代码:
class Solution:
def search(self, lst:list, target):
left, right = 0, len(lst) - 1
while left < right:
mid = (right - left) // 2 + left
if target > lst[mid]: # 查找的目标值在二分之后的数组的右边
left = mid + 1 # 则此时左侧一半的数组舍弃,left变成mid+1,取右侧数组继续二分
elif target < lst[mid]:
right = mid - 1
else:
return mid
return False
target = 5
lst = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
print(Solution().search(lst, target))