查找最接近的元素,思路及题解

题面:

在一个非降序列中,查找与给定值最接近的元素。

输入

第一行包含一个整数n,为非降序列长度。1 <= n <= 100000。
第二行包含n个整数,为非降序列各元素。所有元素的大小均在0~1000000000(1e9)之间。
第三行包含一个整数m,为要询问的给定值个数。1 <= m <= 100000。
接下来m行,每行一个整数,为要询问最接近元素的给定值。所有给定值的大小均在0~1000000000(1e9)之间。

输出

m行,每行一个整数,为最接近相应给定值的元素值,保持输入顺序。若有多个值满足条件,输出最小的一个。

样例输入

3
2 5 8
2
10
5

样例输出

8
5

思路:

第一步:三看定乾坤

1.一看题面,就看到了“非降序列”不用排序,nice。

2.再看题面,0~1000000000(1e9) 不用开long long

3.三看题面,1<=n,m<=100000,暴力肯定过不了,要用二分查找法

第二步:思考——如何二分

第一种方案:

第一种方案,即用二分查找法找到小于等于目标值的最后一个大于目标值的第一个(或小于目标值的最后一个大于等于目标值的第一个)。但这种方法需要调试很久很麻烦,所以我没有用这种方法。

第二种方案:

这种方案可以说是“懒人做法”,即用s数组储存分界点,再用二分查找法查找s数组中的特殊位置,然后做特殊判断,再输出就行了。

代码如下:

#include <bits/stdc++.h>
using namespace std;
int n, m;
int a[100001];
int s[100002]; 

int main()
{
	scanf("%d", &n);
	a[0] = 0;
	for(int i = 1; i <= n; i++)
	{
		scanf("%d", a + i);
		s[i - 1] = a[i - 1] + a[i]; //储存分界点
		s[i - 1] /= 2;              //
	}
	s[0] = -1;  //储存特殊分界点
	s[n] = 1e9; //
	scanf("%d", &m);
	while(m--)
	{
		int x, l, r;
		scanf("%d", &x);
		l = 0;
		r = n;
		while(l <= r) //二分查找法 查找特殊位置
		{
			int mid = (l + r) / 2;
			if(x <= s[mid])
				r = mid - 1;
			else
				l = mid + 1;
		}
		if(l > 1) //特殊判断
		{
			if(x > s[l - 1] && x <= s[l]) //特殊判断
				printf("%d", a[l]);
			else
				printf("%d", a[l - 1]);
		}
		else
			printf("%d", a[l]); 
		if(m >= 1)
			printf("\n"); 
	}
	return 0;
}

注意:

1.第一个特殊判断是必要的,如果没有,会输出很奇怪的数(比如0)。

2.第二个特殊判断是为了确保不会出现特殊情况,但不是必要的

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值