二分法的详解与拓展

 

目录

 1.在一个有序数组中,找某个数是否存在

 2.在一个有序数组中,找大于等于某个数最左侧的位置

 3. 在一个数组中,找小于等于某个数最右侧的位置

 4. 局部最小值问题

1.在一个有序数组中,找某个数是否存在

   public static boolean exist(int[] sortedArr, int num) {
		if (sortedArr == null || sortedArr.length == 0) {
			return false;
		}//如果数组为空或者数组长度为0,错误
		int L = 0;//定义范围的左边界
		int R = sortedArr.length - 1;//定义范围的右边界
		int mid = 0;
		while (L < R) {
			mid = L + ((R - L) >> 1);//数组的中间值,这样操作可以防止溢出
			if (sortedArr[mid] == num) {
				return true;//如果数组的中间值正好等于待查找的数字,直接返回
			} else if (sortedArr[mid] > num) {
				R = mid - 1;//如果数组的中间值大于待查找的数字,右边界更新为数组的中间值-1
			} else {
				L = mid + 1;//如果数组的中间值小于待查找的数字,左边界更新为数组的中间值+1
			}
		}
		return sortedArr[L] == num;
	}

       这个是二分法的基础应用,也叫折半查找,每次砍一半,对算法的时间复杂度进行分析,每次对数组砍一半,最多直到最后只有一个,算法的时间复杂度为O\left ( logn \right ),空间复杂度为O\left ( 1 \right )

 2.在一个有序数组中,找大于等于某个数最左侧的位置

public static int nearestIndex(int[] arr, int value) {
      int L = 0;//查找范围的最左侧
      int R = arr.length - 1;//查找范围的最右侧
	  int index = -1;//待查找位置初始化
	  while (L < R) {
		  int mid = L + ((R - L) >> 1);//定义中间位置
		  if (arr[mid] >= value) {//如果中间位置的值大于等于给定数字(在给定值的右侧寻找,不断逼近)
			 index = mid;//将中间位置赋值给待查找位置
			 R = mid - 1;//范围的最右侧更新为中间值-1,在左侧查找
	  } else {
			 L = mid + 1;//如果中间位置的值小于给定数字,将范围的最左侧更新为中间值+1
	       }
	  }//不断循环迭代,直到二分完毕,找到大于等于给定值的最左侧位置,返回
		return index;
}

       对于这个问题可以利用二分法进行求解,不断二分,缩小范围,到二分完毕时即可找到大于等于给定值最左侧的位置。

  3. 在一个数组中,找小于等于某个数最右侧的位置

public static int dichotomyRightIndex(int[] arr,int target) {
	//如果数组长度小于1或数组为空,错误
	if(arr == null || arr.length <1 ) {
		return false;
	}
    int L = 0;//查找范围的最左侧
	int R = arr.length - 1;//查找范围的最右侧
	int mid = L + ((R - L) >> 1);
	int finalIndex = -1;
	while(L <= R) {
		if(arr[mid] <= target) { //右侧可能还有答案,继续二分,先记录当前位置(在给定值的左侧寻找,不断逼近)
			finalIndex = mid;
			L = mid+1;
			mid = L + ((R - L) >> 1);
		}else { // 答案在左侧
			R = mid -1;
			mid = L + ((R - L) >> 1);
		}
	}
	return finalIndex;
}

  4. 局部最小值问题

       局部最小值问题就是对于一个无序的数组,找到局部最小值(局部最小值指的是对于一个数字,如果它比左右两个数字都小,那么它就是局部最小值),找寻局部最小值可以使用二分法进行求解,相对于遍历来说,时间复杂度要小很多。根据数组左右两侧的变化趋势进行查找,不断更新数组两侧的位置,直到找到局部最小值 。

public static int getLessIndex(int[] arr) {
		if (arr == null || arr.length == 0) {
			     return -1; 
		}//如果数组为空或者长度为0,此时不存在局部最小值,直接返回
		if (arr.length == 1 || arr[0] < arr[1]) {
			     return 0;
		}//如果数组的长度为1或者数组的第一个数字小于数组的第二个数字,那么直接返回数组的第一个位置
		if (arr[arr.length - 1] < arr[arr.length - 2]) {
			return arr.length - 1;//如果数组的最后一个数字小于它的前一个数字,那么最后一个数字就是局部最小值,直接返回它的位置
		}
        //如果上面的情况均不存在,进行下面的操作,根据增减趋势进行查找
        //此时最左侧呈下降趋势,最右侧呈上升趋势,中间一定存在局部最小值
		int left = 1;//查找范围的最左侧位置
		int right = arr.length - 2;//查找范围的最右侧位置
		int mid = 0;//查找范围的中间位置初始化
		while (left < right) {
			mid = left+((right-left)>>1);//查找范围的中间位置赋值
			if (arr[mid] > arr[mid - 1]) {//当数组中间位置的值大于中间位置左侧的值,那么中间位置呈上升趋势,此时右侧范围缩小为中间值-1;
				right = mid - 1;
			} else if (arr[mid] > arr[mid + 1]) {//当数组中间位置的值大于中间位置右侧的值,那么中间位置呈下降趋势,此时左侧范围缩小为中间值+1
				left = mid + 1;
			} else {
				return mid;//如果中间位置的值同时小于左侧和右侧的值,直接返回中间值就是局部最小值
			}
		}
		return left;//循环结束后返回范围左侧或右侧位置的值为结果
	}
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

互联网的猫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值