【计蒜客】基础算法入门之二分查找

时间:2022-01-31 14:41:46

很想写一个很好的文章引子,但是囿于语文水平有限,写不出什么好东西来,干脆就随便写点东西吧。之前写的文章都是关于爬虫的,爬虫虽好,但是写来写去就是那些东西,是时候学习点新东西了!现在自己很缺关于算法的知识,于是就上计蒜客学习了基础算法入门,但是苦于它教学用的是C++,而我大一学过C++,现在早就忘光了。于是我将写几篇系列文章,将计蒜客上面的C++算法改写成Python。

这是第一篇文章《二分查找》

以下文字摘自计蒜客


二分查找,也叫做二分搜索法,是通过不断缩小解可能存在的范围,从而求得问题最优解的方法。接下来,我来带大家学习如何实现二分查找算法。二分查找一般要着重确认在有序数组或序列中找不到给定值、或者待查数组中有重复元素时对计算结果的要求。

这次我们来实现的题目是,给定一个单调非递减数组,和一个要插入的元素,算出它应该插入的位置。比如一个数组{1, 3, 4, 5, 7, 8, 8, 9, 10, 13},如果要插入的元素是6,那么就应该放在现在7所在的位置;如果是8,就应该放在第一个8所在的位置;如果是14,则应该放在13的后面。

代码已经实现了整体的框架,下面来跟随我一步步实现算法的核心代码。首先我们进入binary_search的函数内部,第一行代码定义了二分查找常用的三个变量:left, right和mid。

<span style="font-size:18px;">int left = 0, right = len - 1, mid;</span>
之后我们会不断缩小left到right之间的距离,减少可行区间的范围,直到left和right相等时就是我们所需要的结果。

第一步:请在while循环之后的第一行计算更新mid的值。特别提醒:二分查找的实现方法并不唯一,我们在这里只是举一个实现的例子,请读者尽可能跟随我的思路,将代码的空缺处逐步完善。


第二步:算出mid的位置后,我们需要判断要去左半部分继续计算还是去右半部分继续计算。由于输入的数组是单调非递减的,也就是后面的元素一定不会比前面的小,那么我们首先就要比较mid位置的元素与待查元素的大小关系。接下来我们要实现if语句的逻辑,当待查元素比中间元素不大时修改right的值。


第三步:实现了去左半部分继续查找的逻辑之后,我们继续实现右半部分的逻辑。紧接着刚才的if语句,我们用else代码块和修改left值来实现期望的逻辑。


第四步:我们已经实现了大部分的二分查找的逻辑,left就是计算的结果。接下来我们继续处理边界情况。如果待查元素超过数组中的最大值时,返回的下标应该是数组最后一个下标的靠后一个位置。我们需要比较待查元素和数组最后一个元素的大小,如果待查元素更大的话需要将left结果加1。

用if语句实现这个逻辑吧。


恭喜你!你已经实现了一个基本的二分查找算法。

二分查找的具体实现细节往往和题目的要求相关,读者要多多进行二分查找相关题目的练习,只有彻底理解二分的思想才能以不变应万变,正确实现各种姿势的二分查找哈。


下面就直接贴我改写的Python代码了:

#给定一个从小到大排序的列表num,再给定一个数字target,让你指出这个target该在num的哪个位置?索引从0开始
num=[1, 3, 4, 5, 7, 8, 8, 9, 10, 13,16,18,22]def binary(num,target):m=len(num)left=0;right=m-1;mid=0while left<right:mid=(left+right)/2 #与中间的数对比大小if target<=num[mid]: #如果target比中间数小,说明target在num的左半部分right=mid #所以右边大数改为原来num的中间数else:left=mid+1 #同上if target>num[m-1]: #如果target比num最大的数还大,则输出为m-1left+=1 #也可以为left=mreturn leftprint binary(num,17)#输出11,排在16和18之间


其实这个二分查找的逻辑很简单,上面的例子就很像电视节目里面的猜一个商品的价格,主持人告诉你一个范围,然后你要用最少的次数猜中数字,那么你每次都猜最小和最大数字的中间数字。上面的代码就是这样意思。

over。