80岁老奶奶都能看懂的算法系列①——二分法查找

一.算法简介

这是一个快速搜索的方式,也是一个比较常见和基础的算法。目的是寻找一列集合中的某一个元素的位置,一个检索

假设这里有一列集合,集合里面有n个元素,如何找到目标元素a的位置?

当然,这个集合还是有讲究的,一定是严格单增或单减的集合列!这也是二分法的使用条件。

(本文用单增来说明,单减类似处理

普通人的思想就是一个一个比对:从集合中的一个元素开始,若第i个元素就是a,则输出i

后来这个想法又有了新的改进,也就是二分搜索。二分搜索就是对半砍,舍掉一半,大大增加了效率。

思路如下:

 !!!核心就是和中间元素比大小!!!

(1)先找到中间的元素

(2)做一下简单的高中生都会的分类讨论

        ①若中间元素等于目标元素,恭喜你,直接中奖!直接返回中间元素的下标

        ②若中间元素大于目标元素,说明你的饼画大了,目标元素在第一个集合中,对第一个集合中间元素继续进行比大小操作

        ③若中间元素小于目标元素,说明你的饼画小了,目标元素还未涵盖进去,因此目标元素在第二个集合中,对第二个元素进行继续比大小操作

        tips:这里涉及到一个循环,那么就涉及到如何跳出循环。因为整个集合的数字不会变,做运算的是下标,所以就设定左边下标小于等于右边下标时(一定要有等于,后面会解释),循环进行,不符合条件就跳出循环。

(3)若题目给你开了一个小玩笑,集合里面根本没有你要的元素,则返回-1

这就是二分法的步骤了,请注意一个细节,返回值的问题,什么时候返回,一个是特殊情况,没有目标元素,另一个就是目标元素等于中间元素,这也是循环结束的条件。

二.基本格式(八股文

int down =0;
int up =nums.size()-1;
while(up>=down){
    int mid=(up-down)/2+down;
    int a=nums[mid];
    if(a==target)
        return mid;
    else if(target>a)
        down=mid+1;
    else
        up=mid-1;
}
return -1;

解释:

        第一步先定义好集合的左端的下标down,定义为0;再定义集合的右端下标up,为集合的长度-1(因为我们第一个元素下标是从0开始的,所以每个元素下标相对应的要-1)

        第二步就是找中间元素a,用while循环做,先找到中间元素的下标mid。

        中间元素下标的寻找方法很简单,一种是(首+尾)/2,另一种是首+(尾-首)/2我们通常会使用后者来计算中间元素下标,因为这样可以有效的防止数据的溢出。让下标对应好集合中的元素。

        然后就是比较大小了,首先注意是目标元素和中间元素比大小,不是中间元素的下标和目标元素比大小。是谁这么铸币,我不说。

        若中间元素等于目标元素,返回下标mid,若中间元素小于目标元素,取第二个集合,也就是让集合的左端变成中间元素的下一个元素(用下标来解释就是让新集合down=mid+1),然后用else表示剩下的情况,即中间元素大于目标元素,让集合的右端变成中间元素的前一个元素(用下标来解释就是让新集合up=mid-1

三.一些细节(后续如果有新问题会继续补充的

①关于while的判断条件是否带等号?

        我的建议是一定要带的,因为在代码运行的阶段,区间长度是不断的减小的,跳出循环的上一步一定是左边下标down=右边下表up,在数学中表示的是只有一个数的集合(区间),也就是一个点,这样,下标值即可以取左down,也可以取右up,(左右都是相等的数)也是防止自己混淆

②关于重新定义集合的上下界线,为什么要mid+(-)1,而不等于mid?

        因为如果你直接让up=mid或者down=mid,区间的可能会一直不变,对mid进行加减处理也就是为了让区间长度严格单减,防止陷入死循环。

        例如:对于集合[1,2,3],你要找3,第一步,down=0,up=2;mid=0+(2-0)/2=1

        而mid所对的元素为2,2<3,所以取第二个集合

        第二个集合的down=mid=1;up依然是2;新mid=1+(2-1)=1(这里除是计算机的除,取的是整数部分)

        而mid所对的元素为2,2<3,所以取第二个集合

        ……

        看见没?开始循环了,所以交上oj是的结果是超时

        所以防止超时的一个手段就是新的集合不包含中间元素,取第一个集合就是mid-1,第二个集合就是mid+1.

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值