二分练习题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;
}