C++ STL lower_bound 函数使用

给定一个长度为 n 的序列 A,A 中的数各不相同。对于 A 中的每一个数 AiAi,求:

min1≤j<i|Ai−Aj|min1≤j<i|Ai−Aj|

以及令上式取到最小值的 j(记为 PiPi)。若最小值点不唯一,则选择使 AjAj 较小的那个。

输入格式

第一行输入整数n,代表序列长度。

第二行输入n个整数A1…AnA1…An,代表序列的具体数值,数值之间用空格隔开。

输出格式

输出共n-1行,每行输出两个整数,数值之间用空格隔开。

分别表示当i取2~n时,对应的min1≤j<i|Ai−Aj|min1≤j<i|Ai−Aj|和PiPi的值。

数据范围

n≤105n≤105,|Ai|≤109|Ai|≤109

输入样例:

3
1 5 3

输出样例:

4 1
2 1

 

找到题目用直接暴力法求最小值,会超时

#include <iostream>
#include <algorithm>
#include <cmath>
#include <climits>
using namespace std;

const int N = 100010;

int main()
{
	int n;
	int arr[N];
	scanf("%d", &n);
	for (int i = 0; i<n; i++) {
		scanf("%d", &arr[i]);
	}

	int res, tempj=0;
	for (int i = 1; i < n; i++) {
		res = INT_MAX;
		for (int j = 0; j < i; j++) {
			if (abs(arr[i] - arr[j]) < res || (abs(arr[i] - arr[j])==res && arr[j]<arr[tempj])){
				res = abs(arr[i] - arr[j]);
				tempj = j;
			}
		}
		printf("%d %d\n", res, tempj + 1);

	}
}

 因为这里的每一个数都不相同,而且具有顺序性,所以可以动态维护一个set,通过 lower_bound函数找到一个比该元素大和一个比该元素小,取绝对值最小的即可

这里要注意一些细节,为了避免边界,比如在lower_bound(value)的时候没有比value大的数,以及以及value就是最小的数,只有一个数比value大,在iter--的时候会出问题,所以为了避免边界,像容器中塞入两个INT_MAX, INT_MIN哨兵,但是这个时候在运算的时候可能会爆INT,需要用long long来存

同时注意题目中数组的下标是从1开始。

#include <iostream>
#include <climits>
#include <set>
typedef long long LL;
using namespace std;

int main()
{
	int n, value;
	scanf("%d", &n);
	set<pair<int,int>> s;                             // set默认按value从小到大排序
	s.insert({ INT_MAX,0 });                          // 最大值哨兵
	s.insert({ INT_MIN,0 });                          // 最小值哨兵
	for(int i=0;i<n;i++){
		scanf("%d", &value);
		if (i > 0) {
			auto it = s.upper_bound({ value,0 });     // 返回大于等于value 最小的那一个数
			auto jt = it;
			jt--;
			LL rightValue = (LL)it->first - (LL)value;
			LL leftValue =  (LL)value - (LL)jt->first;
			if (leftValue <= rightValue)
				printf("%lld %d\n", leftValue, jt->second+1);
			else
				printf("%lld %d\n", rightValue, it->second+1);
		}
		s.insert({value,i});
	}
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值