【C++算法竞赛】二分查找

我是黑洞极客,欢迎来到算法竞赛系列!(先赞后看,养成习惯!)

二分查找

引言

对于查找一个数,我们在编程中会使用枚举,BUT,枚举效率太低了!这个时候就要运用另一个查找算法:二分查找

也许你对 “二分查找” 很陌生,但你其实经常会用到:

当你猜数字时,会从中间猜,再根据提示压缩答案的范围;

当你查字典时,会先翻一页,看看你要找的词在这之前还是之后。

这都是二分的思想。

介绍

二分查找(Binary Search),又称折半查找,是一种效率较高的查找方法。但是,折半查找要求线性表必须采用顺序储存结构,而且表中元素按关键字有序排列。该算法时间复杂度为O(logn)。

顾名思义,二分,就是不断减半,直到范围缩小到只有一个数,那个数就是答案。

代码框架

int find(int x, int *a, int n) // x为目标数,a为数组(下标从1开始),n为数组长度 
{
	int ans = -1; // 答案
	int l = 1, r = n; // 左边界与右边界 
	while (l <= r)
	{
		int mid = (l + r) / 2; // 中间值 
		if (check(mid)) r = mid; // check()判断mid是否满足题意,是在左边 
		else l = mid + 1; // 不是在右边 
	}
	ans = l; // 锁定答案
	return ans; 
}

这段代码挺长的,每次使用都要调用很麻烦,我懒得写为了简化代码,STL中有这两个函数:

upper_bound() & lower_bound()

upper_bound(begin, end, value)
lower_bound(begin, end, value)

begin 是数组的第一个元素的地址,end 是数组的最后一个元素的地址,value 是目标数值

upper_bound() 寻找的是数组中第一个大于目标值的数的地址

lower_bound() 寻找的是数组中第一个大于等于目标值的数的地址 

而又因为返回的是地址,所以要减去begin。

这时,有人就要问了:那找最后一个小于和最后一个小于等于目标值的数怎么办?

很简单,第一个大于等于的就是最后一个小于等于的,减一后就是最后一个小于的。如果不理解的话,再多想几遍。

算法例题

查找

题目描述

输入 n 个不超过 10^9 的单调不减的(就是后面的数字不小于前面的数字)非负整数 ,然后进行 m 次询问。对于每次询问,给出一个整数 q,要求输出这个数字在序列中第一次出现的编号,如果没有找到的话输出 -1 。

输入格式

第一行 2 个整数 n 和 m,表示数字个数和询问次数。

第二行 n 个整数,表示这些待查询的数字。

第三行 m 个整数,表示询问这些数字的编号,从 1 开始编号。

输出格式

输出一行,m 个整数,以空格隔开,表示答案。

样例

输入
11 3
1 3 3 3 5 7 9 11 13 15 15
1 3 6

输出
1 2 -1

解题思路

这是经典的二分查找题,与正常二分不同的是,目标值不一定在数组里。解决方法也很简单,如果在数组里,那必然:x == a[ans],判断一下就可以了。

题解
#include <bits/stdc++.h>
using namespace std;

int a[1000010];

int main()
{
	int n, m;
	scanf("%d%d", &n, &m);
	for (int i = 0; i < n; i++) scanf("%d", &a[i]);
	while (m--)
	{
		int x;
		scanf("%d", &x);
		int ans = lower_bound(a, a+n, x) - a;
		if (x == a[ans]) printf("%d ", ans+1);
		else printf("-1 ");
	}
	return 0;
}

走到这里,我们成功GET到了二分查找,下次见,拜拜!

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值