灵活应用二分查找
前言
采用创新方式,精选趣味、实用性强的例子,从不同难度、不同算法、不同类型和不同数据结构进行总结,全面提升算法能力。
例1.查询区间
给定一个包含若干个区间的List数组,长度是1000,如[500,1500],[2100,3100]。给定一个number,判断number是否在这些区间内,返回True或False
示例:输入List=[[100,1100],[1000,2000],[5500,6500]]和number=6000,输出True,因为6000在区间[5500,6500]
输入List=[[100,1100],[2000,3000]]和number=3500,输出False,因为3500不在List的任何一个区间中
代码如下(示例):
class Solut:
def sol(self,list,num):
high = len(list) - 1
low = 0
while high >= low:#进行二分查找,直到 `high` 小于 `low` 为止
if 0 < (num - list[(high + low)//2][0]) <= 1000:#计算中间元素的索引 `(high + low) // 2` 并检查中间元素代表的区间是否包含 `num`
return "True"
elif 1000 < num - list[(high + low)//2][0]:#查找的区间可以缩小到列表的后半部分
low = (high + low)//2 + 1
elif 0 > num - list[(high + low)//2][0]:#查找的区间可以缩小到列表的前半部分。
high = (high + low)//2 -1
return "False"
if __name__ == '__main__':
num = 6000
list = [[100,1100],[1000,2000],[5500,6500]]
ss = Solut()
a = ss.sol(list,num)
print(a)
得到的结果:True
例2.经典二分查找问题
在一个排序数组中找目标数,返回该目标数出现的任意一个位置,如果不存在,则返回-1
示例,输入nums=[1,2,2,4,5,5],目标数target=2,输出1或2;输入nums=[1,2,2,4,5,5],目标数target=6,输出-1
代码如下(示例):
class Solut:
def sol(self,nums,target):
if len(nums) == 0:
return -1
start = 0
end = len(nums) - 1
while start + 1 < end:#使用一个 `while` 循环来不断缩小搜索范围。在每次循环中,计算中间元素的索引 `mid`,并将其与目标值进行比较
mid = start + (end - start)//2
if nums[mid] == target:
end = mid
elif nums[mid] < target:
start = mid
else:
end = mid
if nums[start] == target:
return start
if nums[end] == target:
return end
return -1
if __name__ == '__main__':
ss = Solut()
nums = [1,2,2,4,6]
x = ss.sol(nums,2)
print(x)
得到的结果:1
总结
以上是二分查找的案例
二分查找的思路:
-
边界检查: 如果数组
nums
为空(长度为0),则直接返回-1
,表示找不到目标值。 -
初始化搜索范围: 使用两个指针
start
和end
来表示数组的搜索范围。开始时,start
指向数组的第一个元素,end
指向最后一个元素。 -
二分查找: 使用一个
while
循环来不断缩小搜索范围。在每次循环中,计算中间元素的索引mid
,并将其与目标值进行比较。- 如果
nums[mid]
等于target
,则更新end
为mid
,这意味着目标值可能在左半部分或就是当前位置。 - 如果
nums[mid]
小于target
,则更新start
为mid
,因为目标值可能在右半部分。 - 如果
nums[mid]
大于target
,则不改变start
,但更新end
为mid - 1
,因为目标值不可能在右半部分(因为数组是有序的)。这样,循环会继续进行直到找到目标值或确定目标值不存在于数组中。
- 如果
-
检查结果: 在循环结束后,检查
nums[start]
和nums[end]
是否等于目标值。如果等于,则返回相应的索引;否则返回-1
表示找不到目标值。