【蓝桥杯知识点】二分查找(超超超详细,再也不会错啦)

        考完了计算机三级,蓝桥杯和数学建模的学习也要恢复常态啦!今天,我们来了解一种相对简单但容易出错的算法——二分查找。这里还有一些小方法让二分查找没有那么容易出错,开始学习吧啦啦啦!

PS: 文章主要参考:b站 一只会code的小金鱼 的视频(真的讲得超级超级详细!!!很适合大一没接触过算法的小白学习,而且up的声音也很好听很好听!!!墙裂推荐!)

 基本思路

 

如上图:

查找的对象是一个已经排列好顺序的数的序列,这里要想像一个不存在的红蓝边界,要找的那个数就是红蓝边界,为了找到那个数,先找头尾l和r(-1,n),再找一个中间值,即m=\frac{l+r}{2},如果m属于蓝色,那么头就变成m,如果属于红色尾就变成m,依次查找直到头+1=尾

  l                            I                                                     r   

初始:l指向蓝色区域,r指向红色区域

循环:l,r快速向红蓝边界靠近,保持lr颜色不变

时间复杂度:O(log n) 

注意:l初始位置为-1,r的初始位置为N,防止出现如下情况:

             5         5            8             9                      

在上面的数组中查找<=4的数出现的位置,如果l初始=0,就会出现错误

一定要让l初始在蓝,r初始在红!

      I        5         5           8              9                           

l初始位置为-1,r的初始位置为N,则黄色即为边界,程序马上退出循环体

核心就是这段伪代码啦:

注意:Isblue中,blue的判断条件 是blue的条件,如<5(下图例1)

 这些查找都可以用c++中 的库函数,但二分题型很多,还是掌握根本比较好

解题步骤

精析一组题

例:

数组:     3      4      4      5      5       5         6         7     

分析红蓝条件,找到边界,找到第一个>5的元素的下标

数组:     3      4      4      5      5       5     I     6         7     

下标:     1      2      3      4      5       6           7         8

   主体:

int l=0,r=9;
while(l+1!=r)
{
   int mid (l+r)/2;
   if(isblue(q[mid]))
    {
       l=mid;
    }
   else r=mid;
   if(arr[l]==5)
   {
    return r;
   }
}

isblue:

bool isblue(int x)
{
    if(x<=5)
     return true;
    else 
     return false
}

 题目变形:

数组:     3      4      4      5      5       5         6        7     

分析红蓝条件,找到边界,找到第一个<=5的元素的下标

数组:     3      4      4      5      5       5     I     6         7     

下标:     0      1      2      3      4       5           6         7       //注意下标变成1了

int l=-1,r=8;
while(l+1!=r)
{
   int mid (l+r)/2;
   if(isblue(q[mid]))
    {
       l=mid;
    }
   else r=mid;
   if(arr[l]==5)
   {
    return l;
   }
}
bool isblue(int x)
{
    if(x<=5)
     return true;
    else 
     return false
}

例题 数的范围

题目:

 

答案:

#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;

const int N=100010;

int n,q;
int arr[N];

//数组中的数是num,被询问数是x 
bool isBlue1(int num,int x)
{
	if(num<x) return true;
	else return false;
}

//第一个二分查找的是 被询问数第一次出现的位置(下标) 
bool isBlue2(int num,int x)
{
	if(num<=x) return true;
	else return false;
}

//第二个二分查找的是 被询问数最后一次出现的位置(下标)  
int binary_search1(int q[],int len,int x)
{
	int l=-1,r=len;
	while(l+1<r)
	{
		int mid=(l+r)/2;
		if(isBlue1(q[mid],x))
		{
			l=mid;
		}
		else r=mid;
	}
	if(arr[r]==x) return r;
	else return -1;
}

int binary_search2(int q[],int len,int x)
{
	int l=-1,r=len;
	while(l+1<r)
	{
		int mid=(l+r)/2;
		if(isBlue2(q[mid],x))
		{
			l=mid;
		}
		else r=mid;
	}
	if(arr[r]==x) return l;
	else return -1;
}



int main()
{
	scanf("%d %d",&n,&q);
	for(int i=0;i<n;i++)
	{
		scanf("%d",&q[i]);
	}
	
	while(q--)
	{
		int x;
		scanf("%d",&x);
		int res1=binary_search1(arr,n,x);//查找数起始下标 
		//优化:
	    if(res1==-1)
	    {
		  printf("-1 -1\n");
		  continue;
	    } 
		int res2=binary_search2(arr,n,x);//查找数终止下标 
	}

	printf("%d %d\n",res1,res2);
	return 0;
 } 

  • 15
    点赞
  • 30
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值