对半切快速解题——二分法

如何快速提高算法效率?

在某些实际问题中,我们可以考虑二分法。

目录

1. 二分法求解问题

1.1 存在问题

1.2 无序数组局部最小问题


1. 二分法求解问题

1.1 存在问题

        题目:查找某个数在有序数组中是否存在

1.1.1 算法原理

        找到数组中间位置mid,对比 arr[mid]=x 和题目所求的数 num 的大小。如果 num>x,说明所找的数一定在数组右半部分;如果 num<x,说明所找的数一定在数组左半部分。接着在右半部分/左半部分继续进行二分,直到找到 x 或二分到只剩一个数。

1.1.2 算法过程图示

        假设有序数组为[2 3 4 8 16 19 23 35 39 45 56],num=45。

        数组长度为N=11。

        首先min=0,max=10,mid=N/2=11/2=5,找到arr[5]=19,比较19<45,因此45如果存在,那么一定是在19右侧的数组中,因为数组是有序的,19左侧的数组是全部小于19的。接着min=mid+1=6,max=10,mid=(min+max)/ 2 = 8 ,找到 arr[8]=39,比较39<45,因此45如果存在,那么一定是在39右侧的数组中。接着min=mid+1,max=10,mid=(min+max)/ 2 = 9,找到 arr[9]=45,因此找到所求数字。

        时间复杂度为O(logN)

1.1.3 算法核心代码


import java.util.Arrays;

public class BSExist {
	public static boolean exist(int[] sortedArr, int num) {
		if(sortedArr==null||sortedArr.length==0){
			return false;
		}
		int min=0;
		int max=sortedArr.length-1;
		int mid=0;
		while(min<max) {
			mid=(min+max)/2;
			if(sortedArr[mid]==num) {
				return true;
			}else if(sortedArr[mid]>num) {
				max=mid-1;
			}else {
				min=mid+1;
			}
		}
		return sortedArr[min]==num;
	}
	
	
	
	public static void main(String[] args) {
		int[] arr = {2,3,4,8,16,19,23,35,39,45,56};
		System.out.println(Arrays.toString(arr));
		System.out.print(exist(arr,9));
		
	}

}

1.2 无序数组局部最小问题

1.2.1 局部最小问题

数组长度为N,无序,任意相邻数不相等

①数组头部(下标为0、1):如果arr[0]<arr[1],则arr[0]是局部最小

②数组尾部(下标为N-2、N-1):如果arr[N-1]<arr[N-2],则arr[N-1]是局部最小

③数组中部(非头部,非尾部):如果arr[x]<arr[x-1],arr[x]<arr[x+1],则arr[x]是局部最小

1.2.2 算法原理

        第一步判断①、②情况能否找到局部最小,如果不能,则局部最小一定在中间,如下图所示,趋势一开始是下降,最后是上升,说明中间部分一定存在极值,即局部最小

        接着二分数组,按照第一步继续判断局部最小,以此类推。

1.2.3 算法过程图示

例如数组[6 5 1 2 4 3 7 8]

        第一步判断下标为0、1以及下标为6、7是否存在局部最小,如图可知不存在。接着对数组进行二分,min=0,max=7,mid=(0+7)/2=3,此时查看下标为3的数arr[3]=2左右两边的变化趋势,如图得到左边可能存在局部最小。再对左边部分数组进行二分,min=0,max=3,mid=(0+3)/2=1,此时查看下标为1的数arr[1]=5左右两边的变化趋势,如图得到右边可能存在局部最小,此时只有三个数,且变化趋势满足局部最小,则中间的数arr[2]=1为局部最小。

        时间复杂度为O(N)

1.2.4 算法核心代码

public class BSAwesome {
	public static int getLessIndex(int[] arr) {
		if(arr == null || arr.length ==0) {   //判断数组是否为空
			return -1;
		}
		if(arr.length ==1 || arr[0]<arr[1]) {    //查看头部
			return 0;
		}
		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)/2;    //二分
			if(arr[mid]>arr[mid-1]) {   //二分左侧为上升趋势则说明左侧存在局部最小
				right = mid -1;
			}else if(arr[mid]>arr[mid+1]) {   //二分右侧为下降趋势则说明右侧存在局部最小
				left=mid+1;
			}else {
				return mid;//找到局部最小
			}
		}
		return left;
	}
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		int[] arr= {9,5,2,9,8,6,7,1,10};
		System.out.print(getLessIndex(arr));
	}
}

作者:ee在努力
链接:https://juejin.cn/post/7236635197071491128
来源:稀土掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值