计蒜客:L2查找 查找最接近的元素

本文探讨了在非降序序列中查找最接近指定值x的元素的算法问题。通过计蒜客的在线课程示例,指出仅使用`lower_bound`可能会导致错误,并解释了错误的原因。解决方案是结合`lower_bound`的结果进行特判,存储并比较差值,以确定实际最接近的元素。最后强调,在处理这类问题时,需要注意特殊情况的特判以确保正确性。

本题链接:
https://www.jisuanke.com/course/3797/255499
这题的大意是给你一个非降序列,再给你个x,叫你求最接近x的元素

这题很多萌新一看就说:“简单,一个lower_bound解决所有问题。”

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int num[100005];
int main() {
    freopen("closest.in", "r", stdin);
    freopen("closest.out", "w", stdout);
    int n, m, x;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> num[i];
    }
    cin >> m;
    int p1;
    while (m--) {
        cin >> x;
        p1 = lower_bound(num, num + n, x) - num;
        cout << p1 << endl;      
    }
    return 0;
}

结果…

在这里插入图片描述

那么,到底怎么回事呢?

第一步,检查思路。
用lower_bound是没有问题的,但只用lower_bound就会有漏洞。

举个例子,看看这个样例:
3
2 5 8 12
1
9

正确输出是8,但用cpp跑一遍就会知道输出是12。
为什么呢?
因为lower_bound输出的是第一个大于等于要查找的元素值的位置 但是如果最小值出在比它小的呢?这时候就没有“super_lower_bound",只能对返回值进行特判。

所以首先要设一个p2,用来存比p1小的值,再来个d1和d2,用来存两者和x的差,最后来比较两者谁小,最后来输出p1或p2所对应的值。这里又有一个错点:直接输出p1或p2,注意⚠️:我们题要的是,而非位置!!

成体代码如下:

#include <cstdio>
#include <iostream>
#include <algorithm>
using namespace std;
int num[100005];
int main() {
    freopen("closest.in", "r", stdin);
    freopen("closest.out", "w", stdout);
    int n, m, x;
    cin >> n;
    for (int i = 0; i < n; i++) {
        cin >> num[i];
    }
    cin >> m;
    int p1,p2,d1,d2;
    while (m--) {
        cin >> x;
        p1 = lower_bound(num, num + n, x) - num;
        p2 = p1 - 1;
        d1 = 2000000000;
        d2 = 2000000000;
        if(p1 != n)
        {
            d1 = num[p1] - x;
        }
        if(p2 != -1)
        {
            d2 = x - num[p2];
        }
        if(d1 < d2)
        {
            cout << num[p1] << endl;
        }
        else
        {
            cout << num[p2] << endl;
        }
    }
    return 0;
}

最后再来总结一下思路:

  1. 读入
  2. 用lower_bound求出p1
  3. 设好p2,d1,d2
  4. 求出d1,d2
  5. 比较
  6. 输出

所以遇到这种题一定要注意,用了lower_bound或upper_bound之后要注意有没有特殊情况需要特判,才能提高正确率。

祝各位学业进步,马到成功!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值