相关内容:
其余练习题1:https://www.cnblogs.com/rnanprince/p/11743414.html
二分查找(倍增法):https://mp.csdn.net/postedit/102811021
其余练习题2:https://www.cnblogs.com/rnanprince/p/11761940.html
————————————————
二分查找
二分查找也称折半查找(Binary Search),它是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序存储结构,而且表中元素按关键字有序排列。
• 循环条件到底哪一个?
• start <= end
• start < end
• start + 1 < end
• 指针变换到底哪一个?
• start = mid
• start = mid + 1
• start = mid - 1
弄不好就死循环,弄不好边界就失误
怎么办?
模板:
def bin_search(nums, target):
if not nums or target < nums[0] or target > nums[-1]:
return -1
left = 0
right = len(nums) - 1
while left + 1 < right: # 统一都用 <
mid = left + (right - left)//2
if target > nums[mid]: # 左边界> 右边界>=
left = mid # 永远不动,全文通用
elif target < nums[mid]:
right = mid # 永远不动,全文通用
else:
return mid # 等号可以合并到 < 或 > 也可以单独考虑
if nums[right] == target:
return right
if nums[left] == target:
return left
return -1 # 较小的left,较大的right
总结:
1.判断是返回left,还是返回right
因为我们知道最后跳出while (left + 1< right)循环条件是left+ 1 == right。
最后left 和right一定是卡在"边界值"的左右两边
以数组{1, 2, 3, 3, 4,5}为例,
如果需要查找第一个等于或者小于3的元素下标,我们比较的key值是3,则最后left和right需要满足以下条件:
left——>2, right ——>3
我们比较的key值是3,所以此时我们需要返回right 。
所以,最后只需要判断left或right是否等于target即可。
2.判断出比较符号
左边界附近都是>
右边界附近都>=
举例说明:
1.lower_bound1, 则是返回的是被查序列中最后一个 < 查找值的指针
def lower_bound1(nums, target):
if not nums or target < nums[0]: # 只需要判断左边界
return -1
left = 0
right = len(nums) - 1
while left + 1 < right: # 统一都用 <
mid = left + (right - left) // 2
if target > nums[mid]: # 左边界>
left = mid # 不动
else:
right = mid # 不动
if nums[right] < target: # 当target > nums[-1]时
return right
return left # 较小的left,较大的right
2.lower_bound2, 则是返回的是被查序列中最后一个 <= 查找值的指针
def lower_bound2(nums, target):
if not nums or target < nums[0]: # 只需要判断左边界
return -1
left = 0
right = len(nums) - 1
while left + 1 < right: # 统一都用 <
mid = left + (right - left) // 2
if target > nums[mid]: # 左边界>
left = mid # 不动
else:
right = mid # 不动
if nums[left] == target: # 当target == nums[0]时
return left
return right # 较小的left,较大的right
3.upper_bound1, 则是返回的是被查序列中第一个 >= 查找值的指针
def upper_bound1(nums, target):
if not nums or target > nums[-1]: # 只需要判断右边界
return -1
left = 0
right = len(nums) - 1
while left + 1 < right: # 统一都用 <
mid = left + (right - left) // 2
if target >= nums[mid]: # 右边界>=
left = mid # 不动
else:
right = mid # 不动
if nums[right] == target: # 当target == nums[-1]时
return right
return left # 较小的left,较大的right
4.upper_bound2, 返回的是被查序列中最后一个 = 查找值的指针
def upper_bound2(nums, target):
if not nums or target > nums[-1]: # 只需要判断右边界
return -1
left = 0
right = len(nums) - 1
while left + 1 < right: # 统一都用 <
mid = left + (right - left) // 2
if target >= nums[mid]: # 右边界>=
left = mid # 不动
else:
right = mid # 不动
if nums[left] == target:
return left
if nums[right] == target: # 当target == nums[-1]时
return right
return -1 # 较小的left,较大的right
5.upper_bound3,返回的是被查序列中第一个 > 查找值的指针
def upper_bound3(nums, target):
if not nums or target > nums[-1]: # 只需要判断右边界
return -1
left = 0
right = len(nums) - 1
while left + 1 < right: # 统一都用 <
mid = left + (right - left) // 2
if target >= nums[mid]: # 右边界>=
left = mid # 不动
else:
right = mid # 不动
if nums[right] == target: # 当target == nums[-1]时
return -1
return right # 较小的left,较大的right
递归版:
def recursive(arr, low, high, key):
if low > high:
return -1
mid = (low + high) // 2
if arr[mid] == key:
return mid
if arr[mid] < key:
return recursive(arr, mid + 1, high, key)
return recursive(arr, low, mid - 1, key)
下期内容:
其余练习题1:https://www.cnblogs.com/rnanprince/p/11743414.html
二分查找(倍增法):https://mp.csdn.net/postedit/102811021
其余练习题2:https://www.cnblogs.com/rnanprince/p/11761940.html