二分算法详解-------整数二分(java实现)

二分算法主要分为整数二分和浮点数二分。 在处理有关于二分的问题时,所给数组是否满足单调性,只是我们选择使用二分算法的一个充要条件。在解答关于二分的问题时,一个非常重要的步骤便是关于分界点的判断。以下笔者对着两个算法做出详细的分析

一.整数二分

1.算法的基本思想
我们给以将所给区间划分成两个部分,一部分满足某种性质,另一部分不满足该性质。如何找出这个分界点?这个时候便要用到二分的思想。
在这里插入图片描述(1).mid值什么时候为(L+R+1)/2什么时候是(L+R)/2?
在写二分查找算法时,我们首先写check函数,当发现我们需要将L变为mid时,即L = mid,这时我们就返回关于mid的代码将其设置为mid = (L+R+1)/2。反之,当我们发现需要将R变为mid时,即R=mid,这时我们需要将mid设置为mid = (L+R)/2.

(2)为什么mid=(L+R+1)/2 ?
我们假设 mid = (L+R)/2,当R=L-1时,我们会发现mid = L,令L=mid =L,这样会陷入一个死循环。

2…算法模板

/*当区间[l,r]被划分成[l,mid]和[mid+1,r]时使用*/

int b_search(int l,int r){
	while(l<r){
		int mid = (l+r+1)/2;
		if(checked(mid)){
			l = mid;
		} else {
			r = mid-1;
		}
	}
}
/*当区间[l,r]被划分成[l,mid-1]和[mid,r]时使用*/
int b_search(int l,int r){
	while(l<r){
		int mid = (l+r)/2;
		if(checked(mid)){
			r = mid;
		} else {
			l = mid+1;
		}
	}
}

3.例题

数的范围

给定一个按照升序排列的长度为 n 的整数数组,以及 q个查询。对于每个查询,返回一个元素 k的起始位置和终止位置(位置从 0开始计数)。如果数组中不存在该元素,则返回 -1 -1。

输入格式

第一行包含整数 n 和 q,表示数组长度和询问个数。

第二行包含 n 个整数(均在 1∼10000范围内),表示完整数组。

接下来 q 行,每行包含一个整数 k,表示一个询问元素。

输出格式

共 q 行,每行包含两个整数,表示所求元素的起始位置和终止位置。

如果数组中不存在该元素,则返回 -1 -1。

输入样例:
6 3
1 2 2 3 3 4
3
4
5

输出样例:
3 4
5 5
-1 -1

解题思想:
注意题干中所给数组的条件为"升序排列",那么必然可以使用二分查找算法。关键点是check函数的判断条件。
起始点的判断条件:mid值>=query值
终止点的判断条件:mid值<=query值
没有查询到:当while循环截止时,lcopy=rcopy,只需要判断data[lcopy]是否与query值相等即可。

代码:

import java.util.Scanner;

public class Main {
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		int n = sc.nextInt();
		int q = sc.nextInt();
		int[] data = new int[n];
		int[] query = new int[q];
		for(int i=0;i<n;i++) {
			data[i] = sc.nextInt();
		}
		for(int i=0;i<q;i++) {
			query[i] = sc.nextInt();
		}
		sc.close();
		
		for(int i=0;i<q;i++) {
			b_searchStart(0,n-1,query[i],data);
		}
	}
	
	//寻找起始坐标
	public static void b_searchStart(int l,int r,int k,int[] data) {
		int lcopy = l,rcopy = r;
		while(lcopy<rcopy) {
			int mid = lcopy+rcopy >> 1;
			if(data[mid] >= k) {
				rcopy = mid;
			} else {
				lcopy = mid +1;
			}
		}
		
		if(data[lcopy] != k) {
			System.out.println("-1 -1");
		} else {
			System.out.print(lcopy+" ");
			b_searchEnd(l,r,k,data);
		}
	}
	
	//寻找结束坐标
	public static void b_searchEnd(int l,int r,int k,int[] data) {
		int lcopy = l,rcopy = r;
		while(lcopy<rcopy) {
			int mid = (lcopy+rcopy+1) >> 1;
			if(data[mid]<=k) {
				lcopy = mid;
			} else {
				rcopy = mid -1;
			}
		}
		System.out.println(rcopy);
	}
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值