思想:
二分查找又称折半查找。首先,假设表中元素是按升序排列,将表中间位置记录的关键字与查找关键字比较,如果两者相等,则查找成功;否则利用中间位置记录将表分成前、后两个子表,如果中间位置记录的关键字大于查找关键字,则进一步查找前一子表,否则进一步查找后一子表。重复以上过程,直到找到满足条件的记录,使查找成功,或直到子表不存在为止,此时查找不成功。
优缺点
优点是比较次数少,查找速度快,平均性能好;
-
最优时间复杂度:O(1)
-
最坏时间复杂度:O(logn)
其缺点是要求待查表为有序表,且插入删除困难。
#非递归的二分查找
def binary_chop(alist, data):
n = len(alist)
first = 0
last = n - 1
while first <= last:
mid = (last + first) // 2
if alist[mid] > data:
last = mid - 1
elif alist[mid] < data:
first = mid + 1
else:
return mid
return -1
#递归的二分查找
def binary_chop(alist, data):
n = len(alist)
if n < 1:
return -1
mid = n // 2
if alist[mid] > data:
return binary_chop(alist[0:mid], data)
elif alist[mid] < data:
return binary_chop(alist[mid+1:], data)
else:
return mid
二分查找:
class Solution:
def mySqrt(self, x: int) -> int:
if x == 0:
return 0
left = 1
right = x // 2
while left < right:
# 注意:这里一定取右中位数,如果取左中位数,代码可能会进入死循环
# mid = left + (right - left + 1) // 2
mid = (left + right + 1) >> 1
square = mid * mid
if square > x:
right = mid - 1
else:
left = mid
# 因为一定存在,因此无需后处理
return left
牛顿法:
class Solution:
def mySqrt(self, x):
if x < 0:
raise Exception('不能输入负数')
if x == 0:
return 0
# 起始的时候在 1 ,这可以比较随意设置
cur = 1
while True:
pre = cur
cur = (cur + x / cur) / 2
if abs(cur - pre) < 1e-6:
return int(cur)