二分搜索--java

算法描述

前提有序升序数组arr,目标值target
1

i=0,j=len-1 设置左右指针

2

设置中间索引mid=(i+j)/2,mid向下取整

3target=arr[mid] 返回mid
4target<arr[mid],目标在中间索引前段,j=mid-1,返回步骤2
5arr[mid]>target,目标在中间索引后端,i=mid+1,返回步骤2
6i>j,没有找到目标值,返回-1

语言描述

在一个升序数组中,设置左索引i,右索引j,和中间值mid,判断目标值与中间值的大小,1)target>中间值,则target在右侧,i=mid+1;2)target<中间值,则target在左侧,j=mid-1;3)target=中间值,返回mid即可

but 如果所有索引都检查了一遍即i>j,还没有找到,则数组中无该索引,返回-1;

时间复杂度 o(log2^n)

代码实现

int j=arr.length-1;不要忘记 -1

 public int Search(int[]arr,int target){
		int i=0;//左指针
		int j=arr.length-1;//右指针
		while(i<=j){
			int mid=(i+j)/2;//中间数
			if(target<arr[mid]){//目标在左侧
				j=mid-1;
			} else if (arr[mid]<target){//目标在右侧
				i=mid+1;
			}else {
				return mid;//目标=中间值
			}
		}
		return -1;//没找到返回-1
	}

思考

1.i<=j与i<j

2.mid=(i+j)/2的隐患

        与源码补码有关,所以用mid=i+j>>>1

3.代码只用<号--一种规范,牛

算法改进2.0

改进内容

1.j=arr.len

2.i<j

3.j=mid

代码实现

static int BinarySearch(int[]arr,int target){
		int i=0;
		int j=arr.length;//1.j
		while(i<j){//2.i<=j
			int mid=i+j>>>1;
			if (target<arr[mid]){
				j=mid;//3.j=mid-1
			} else if (arr[mid]<target) {
				i=mid+1;
			}else{
				return mid;
			}
		}return -1;
	}

区别.

j含义的改变:

基础:j指向一个元素,也在可查找空间中

进阶:j指向一个边界,不为查找元素

算法改进3.0

代码实现

	static int BinarySearch(int[] arr,int target){
		int i=0;
		int j=arr.length;
		while(1<j-i){
			int mid=i+j>>>1;
			if (target<arr[mid]) {
				j=mid;
			}else{
				i=mid;
			}
		}
		if (arr[i] ==target) {
			return i;
		}else{
			return -1;
		}
	}

改进地方(相较于2.0)

while(i<j){
            int mid=i+j>>>1;
            if (target<arr[mid]){                   //目标值在左边循环内时间复杂度为L
                j=mid;
            } else if (arr[mid]<target) {        //目标值在右边时间复杂度为2L
                i=mid+1;
            }else{
                return mid;
            }

左右两边时间复杂调度不一致,3.0改进判断方式,好处:使左右时间复杂度一致,坏处:当target=arr[mid]出现时,只能循环结束后再判断 

时间复杂\theta(logn)

leftmost

引:二分查找算法对重复元素的处理--找到重复元素的最左索引

语言描述

在找到第一个目标值的前提下,向前查找,if还有目标值,则赋值给candidate,并再次向前查找,知道全部都查找一遍(i>j);

代码实现

public int leftmost(int[] arr,int target){
		int i=0;//左指针
		int j=arr.length-1;//右指针
		int candidate=-1;//获取最左索引
		while(i<=j){
			int mid=(i+j)/2;//中间数
			if(target<arr[mid]){//目标在左侧
				j=mid-1;
			} else if (arr[mid]<target) {//目标在右侧
				i=mid+1;
			}else {//目标=中间值
				candidate=mid;
				//因为想找到最左索引,索引要在该目标前找
				j=mid-1;
			}
		}
		return candidate;//最后返回找到的最左索引值,如果没找到就返回-1;
	}

rightmost

引--想法和leftmost差不多

代码实现

public int rightmost(int[] arr,int target){
		int i=0;//左指针
		int j=arr.length-1;//右指针
		int candidate=1;
		while(i<=j){
			int mid=(i+j)/2;//中间数
			if(target<arr[mid]){//目标在左侧
				j=mid-1;
			} else if (arr[mid]<target) {//目标在右侧
				i=mid+1;
			}else {//目标=中间值
				candidate=mid;
				//因为想找到最右索引,索引要在该目标后找
				i=mid+1;
			}
		}
		return candidate;//最后返回找到的最后索引值,如果没找到就返回-1;
	}

还有p16,要死了,是什么狗屎的脑筋急转弯

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值