二分练习题9 和为给定数 题解

题目描述

给出若干个整数,询问其中是否有一对数的和等于给定的数。

输入格式

共三行:
第一行是整数 \(n(0 \lt n \le 100000)\) ,表示有 \(n\) 个整数。
第二行是n个整数。整数的范围是在 \(0\)\(10^8\) 之间。
第三行是一个整数 \(m(0 \le m \le 2^{30})\) ,表示需要得到的和。

输出格式

若存在和为m的数对,输出两个整数,小的在前,大的在后,中间用单个空格隔开。若有多个数对满足条件,选择数对中较小的数更小的。若找不到符合要求的数对,输出一行“NO”。

样例输入

4
2 5 1 4
6

样例输出

1 5

题目分析

这道题目可以使用时间复杂度为 \(O(n)\) 的双指针法。(有兴趣的同学可以了解一下)
但是我们这里先来讲解 \(O(nlogn)\) 的二分解法。
对于数组 \(a_1,a_2,...,a_n\) 来说,首先我们需要使用 sort 函数给他们从小到大排序。
然后我们可以从 \(1\)\(n\) 遍历坐标 \(i\) ,对于 \(a[i]\) 来说,我们可以在 \([i+1, n]\) 这个区间范围内使用二分来查找是否存在一个元素等于 \(m-a[i]\)
当然咯,我们遍历的时候也要保证 \(a[i] \le m/2\) 就可以了,因为我二分查找的另一个元素肯定 \(\le a[i]\)
实现代码如下:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100010;
int n, m, a[maxn];
// check函数用于二分查找数组a[L,R]中是否存在值为num的元素
bool check(int num, int L, int R) {
    while (L <= R) {
        int mid = (L + R) / 2;
        if (a[mid] == num) return true;
        else if (a[mid] > num) R = mid - 1;
        else L = mid + 1;
    }
    return false;
}
int main() {
    cin >> n;
    for (int i = 1; i <= n; i ++) cin >> a[i];
    cin >> m;
    sort(a+1, a+1+n);   // 给数组a[1]到a[n]范围内的数从小到大排序
    for (int i = 1; i <= n && a[i] <= m/2; i ++) { // 开始遍历a[i]
        if (check(m - a[i], i+1, n)) {  // 对[i+1,n]区间范围内二分查找m-a[i]
            cout << a[i] << " " << m-a[i] << endl;
            return 0;
        }
    }
    puts("NO");
    return 0;
}
posted @ 2019-09-03 00:12  zifeiynoip  阅读(498)  评论(0编辑  收藏  举报