算法——二分查找

280 阅读2分钟

二分查找

基本概念:

二分法,也称为折半搜索对数搜索,是一种在有序数组中查找特定元素的算法。其基本思想是通过不断将查找范围缩小一半,从而快速定位目标元素。时间复杂度为O(logN)

模板:

1.从n个数中查找最后一个<=q的数的下标

最小化查找

从前往后的最后一个或从后往前的第一个,通俗点讲,就是尽量往右找到你想要的数

int find(int q){
	int l=0,r=n+1;
	while(l+1<r){//即l+1=r的时候停止查找
		int mid=l+r>>1;
		if(a[mid]<=q) l=mid;
		else r=mid
	}
	return l;
}

其中l+r>>1 含义为l+r右移一位,即(l+r)/2下取整。

2.从n个数中查找第一个>=q的数的下标

最大化查找

从前往后的第一个或从后往前的倒数第一个,相对的,就是尽量往左找到你想要的数

int find(int q){
	int l=0,r=n+1;
	while(l+1<r){
		int mid=l+r>>1;
		if(a[mid]>=q) r=mid;
		else l=mid;
	} 
	return r;
}

3.浮点二分:

求一个浮点数(-10000<=y<=10000)的三次方根

double find(double y){
	double l=-100,r=100;
	while(r-1>1e-5){//保证精度
		double mid=(l+r)/2;
		if(mid*mid*mid<=y) l=mid;//如果符合题目要求
		else r=mid;
	}
	return l;
}
int mian(){
	double y;scanf("%lf",&y);
	printf("%.3lf\n",find(y));
	return 0;
}

例题:

查找(Luogu P2249)

在这里插入图片描述

题目分析:

因为我们需要在单调不减的非负整数中找多个数字,并且要求使用较快的方式,所以可以想到用二分查找的方法。同时还会想到取消同步流,这也会增高我们代码的效率。

思路:

1.读取输入数组。

2.用循环处理每一次的询问。

3.因为是输出第一次出现的编号,那么可以用最小化查找。

4.考虑找不到的情况。

解答:
#include<iostream>
using namespace std;
const int N=1e6+10;//把数组开大一点

int arr[N];
int find(int q,int a[],int n)//二分模板
{
    int l=0,r=n+1;
    while(l+1<r)
    {
        int mid=l+r>>1;
        if(a[mid]>=q)
        {
            r=mid;
        }
        else
        {
            l=mid;
        }
    }
    if(a[r]==q)//如果找到了
    {
        return r;//返回正确答案
    }
    else
    {
        return -1;
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0),cout.tie(0);
    int n,m;
    cin>>n>>m;
    for(int i=1;i<=n;i++)
    {
        cin>>arr[i];
    }
    while(m--)
    {
        int q;
        cin>>q;
        int t=find(q,arr,n);
        cout<<t<<" ";
    }
    return 0;
}
总结:

二分可以提高查找效率,在要处理的数据量过大的情况下可以考虑这个方法;

要注意用最大化查找还是最小化查找,根据题目意思选择合适的模板。