这道题可以双指针、哈希,但也可以二分,这里就把三种一起讲掉啦!
二分
二分思路
既然要找两个和为 $x$ 的数,那么我们可以把它转换成确定了一个 $y$ 为 $A_i$ 然后快速在 $B$ 中找出 $x - y$ 的问题。
显然我们可以二分查找,算法复杂度为 $O(nlogn)$,可以 $AC$ 。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int a[N], b[N];
int n, m, x;
int main() {
cin >> n >> m >> x;
for (int i = 0; i < n; i ++) cin >> a[i];
for (int i = 0; i < m; i ++) cin >> b[i];
for (int i = 0; i < n; i ++) {
int y = x - a[i];
int l = 0, r = m - 1;
while (l <= r) {
int mid = l + r >> 1;
if (b[mid] == y) {
cout << i << " " << mid << endl;
return 0;
} else if (b[mid] < y) {
l = mid + 1;
} else {
r = mid - 1;
}
}
}
return 0;
}
双指针
双指针思路
我们先简化一下问题,变成求 $A_i + B_j >= x$ 且 $j$ 要最小。
我们用可以一个指针 $i$ 枚举 $A$ 中的所有数,而 $j$ 则用来枚举 $B$,但由于数组是单调递增的,所以如果 $A_i + B_j \ge x$ 那么 $B_{j + 1}$ 到 $B_m$ 就不可能是答案。
所以 $j$ 是只能递减的,如此,我们便可以用 $O(n + m)$ 的时间复杂度通过这道题。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 100010;
int n, m, x;
int a[N], b[N];
int main() {
cin >> n >> m >> x;
for (int i = 1; i <= n; i ++) cin >> a[i];
for (int i = 1; i <= m; i ++) cin >> b[i];
for (int i = 1, j = m; i <= n; i ++) {
while (j >= 0 && a[i] + b[j] >= x) j --;
if (j >= 0 && b[j + 1] + a[i] == x)
cout << i - 1 << " " << j << endl;
}
return 0;
}
哈希
思路
我们可以在输入 $A$ 时把每个数存进哈希表里,对于每个输入的 $B_i$ 看看 $x - B_i$ 是否出现与哈希表即可。
代码
#include <iostream>
#include <cstring>
#include <algorithm>
#include <unordered_map>
using namespace std;
const int N = 100010;
int n, m, x;
int a[N], b[N];
unordered_map<int, int> h;
int main() {
cin >> n >> m >> x;
for (int i = 0; i < n; i ++) {
cin >> a[i];
h[a[i]] = i;
}
for (int i = 0; i < m; i ++) {
cin >> b[i];
if (h.count(x - b[i]))
cout << h[x - b[i]] << " " << i << endl;
}
return 0;
}