文章目录
二分是什么可以干什么?
二分是一种常用的算法技巧,用于在有序数组或有序序列中查找某个元素的位置。
二分算法的基本思路是将查找区间不断缩小,直到找到目标元素或者确定目标元素不存在。具体实现方式是先确定查找区间的左右边界,然后计算中间位置的元素值,如果该值等于目标值,则找到目标元素;如果该值大于目标值,则说明目标元素应该在左半部分查找,反之则在右半部分查找。不断缩小查找区间,直到找到目标元素或者确定目标元素不存在。
于是我们引入红蓝二分的思想来更好的引入二分
一、学习二分思想
二分算法的时间复杂度为 O(log n),其中 n 是数组或序列的大小,相对于暴力枚举的时间复杂度 O(n) 来说,具有更好的时间效率
使用条件和难点
尽管二分算法看起来简单,但实际上它也有一些使用条件和难点:
-
最痛苦的莫过于边界条件:
在实现二分算法时,边界条件是非常关键的。边界条件包括搜索区间的起点和终点,以及中间元素的计算方式。如果边界条件不正确,就可能导致算法出现错误或进入死循环。 -
数组必须有序:
由于二分算法的核心思想是逐步缩小搜索区间,所以必须保证数组是有序的。如果数组无序,则需要先进行排序,这将增加算法的复杂度。 -
最重要的是能看出它能用二分(状态转移设计):
如:动态规划+二分 leetcode.300 这个一般人还真的不知道怎么能用二分,当初我就在想他们的脑子的是什么做的!
题目引入
红蓝二分法
先来简单的二分
现在我要在一个数组中找数:
list_num = [ i for i in range(0,100,2)]
# 找22在这个数组的哪里,或者22有没有在这个数组里面
left = -1
right = len(list_num)
while left+1!=right:
mid = (left+right)//2
if list_num[mid]<=22:
left = mid
else:
right = mid
return left
这就是一个经典的红蓝二分法写出来的,看他的条件left+1!=right,于是我们不会出现left和right相交的情况。
而我们的答案却已经放入了left 和 right 里面了
下面我们来详细解说什么是红蓝二分法
left, right 就是红蓝二分的边界,如名字一样一个是右边的边界,一个是左边的边界。边界不会相交,而只有满足条件left+1==right 时才会相邻。也就是While循环退出的时候
然后是初始left, right时初始值填的是什么:
left:-1
right:len(list)
这样我们就不用去想边界的问题了,应为要么list的区域全被left占领,要么就是被right。
而我们通过红蓝二分的方法很巧妙的绕开了二分的边界问题
五点七边up的视频素材
大家看完应该对二分的很多题都可以解了
解下来我们主要的是去理解状态转移的设计,能写出二分不是什么要的是你能看出这能使用二分。很多算法都是不是你能写,而是你能看出它能用!
二、Python内置的二分函数
这个库是真的好用,而且还是内置的在算法竞赛的时候效果很好
Python中的二分函数可以使用标准库bisect来实现。bisect模块提供了两个函数:bisect_left()和bisect_right()。这些函数使用二分查找算法在有序序列中查找指定元素的位置。
这两个函数的区别在于,当有多个相同的元素时,bisect_left()函数返回第一个出现的位置,而bisect_right()返回最后一个出现的位置。
import bisect
lst = [1, 3, 4, 4, 4, 6, 8, 9]
x = 4
使用 bisect_left() 查找 x 的位置
idx_left = bisect.bisect_left(lst, x)
print("bisect_left(): ", idx_left)
使用 bisect_right() 查找 x 的位置
idx_right = bisect.bisect_right(lst, x)
print("bisect_right(): ", idx_right)
输出:
bisect_left(): 2
bisect_right(): 5
在上面的示例中,列表lst中有多个值为4的元素。
bisect_left()函数返回第一个出现的位置2,
而bisect_right()函数返回最后一个出现的位置5。