【算法】二分查找

二分查找的前提条件是:数组是有序的。

一、基础版(左闭右闭):

待查找值target在[left , right]区间中,所以左右指针不仅表示查找边界,也表示指向的元素可能参与运算。

1)确定左右指针初始值:i=0,j=arr.length-1。

2)while(i<=j):“=”是多考虑一次,即当指针i=j=m指向同一元素

3)中间索引:m=(i+j)/2,此处Java是默认向下取整;但当j取值很大,即Interger.Max_Value-1时,第二次运算可能出错;因此,我们采用无符号运算:右移一位>>>1,这样既可以避免索引为负值,也可以保证向下取整。

3)判断:①arr[m]<target,则i=m+1;表示查找值在右半区域,故左指针后移

                ②target<arr[m],则j=m-1;表示查找值在左半区域,故右指针前移

                ③target=arr[m],则return m;返回查找值的索引

4)当i>j时,跳出循环,返回-1;

java中的binarySearch采用基础版,返回值:-(插入点-+1)

二、改动版(左闭右开):

待查找值target在[left , right)区间中,左指针i与基础版的含义一样;不过右指针j此时仅仅表示查找边界,指向的元素一定不是查找目标。

1)确定左右指针初始值:i=0,j=arr.length。

2)while(i<j):此时不能考虑“=”的情况,否则可能陷入死循环

3)中间索引:m=(i+j)>>>1;

3)判断:①arr[m]<target,则i=m+1;表示查找值在右半区域,故左指针后移

                ②target<arr[m],则j=m;//表示查找值在左半区域,故右指针前移,其指向的m索引在上一次循环已经判断过,不需要再次判断

                ③target=arr[m],则return m;返回查找值的索引

4)当i>j时,跳出循环,返回-1;

时间复杂度:O(log(n));空间复杂度:O(n)

上面两种方法:当目标值在左、右两边进行比较的次数不均一,最好情况和最坏情况的所需时间差距较大;因此基于此,在改动版的基础上进行改进。

三、平衡版(左闭右开):

特点:①不在循环内找target,循环只是缩小范围,当范围内只剩下i时,退出循环,在循环外比较arr[i]与target

           ②循环内的平均比较次数减少了

缺点:原本二分法最好情况时,时间复杂度为O(1);而平衡板最好和最坏情况的时间复杂度都是log(n)

1)确定左右指针初始值:i=0,j=arr.length。

2)while(1<j-i):此时不能考虑“=”的情况,否则可能陷入死循环

3)中间索引:m=(i+j)>>>1;

3)判断:if(target<arr[m]){j=m;}//表示查找值在左半区域,故右指针前移,其指向的m索引在上一次循环已经判断过,不需要再次判断

                else{i=m;}//表示查找值在右半区域,故左指针后移

4)跳出循环后,if(arr[m]==target) {return i;}else{return -1;},则return m;返回查找值的索引

以上版本适合数组中没有重复元素的情况,如果有重复元素,那么返回的索引就不是唯一的。当出现重复元素时,我们就可以在基础版上进行改动分别找到最左侧或是最右侧的值。

四、LeftMost:找到重复元素中最左侧的值

1)在while循环前,定义一个变量临时记录目标值

2)当target=arr[m]时,用变量candidate=m,然后继续向左找,缩小边界j=m-1;

3)循环结束后,返回candidate,当没找到时返回初始值-1。

五、RightMost:找到重复元素中最右侧的值

1)在while循环前,定义一个变量临时记录目标值

2)当target=arr[m]时,用变量candidate=m,然后继续向右找,缩小边界i=m+1;

3)循环结束后,返回candidate,当没找到时返回初始值-1。

利用LeftMost和RightMost可以找到前任--LeftMost(i)-1、后任--RightMost(i)+1、最近邻居、排名、范围查询。

                                

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值