📅  最后修改于: 2023-12-03 14:49:21.573000             🧑  作者: Mango
有一个长度为 $n$ 的整数数组 $a[]$,满足该数组中任意两个元素 $a[i]$ 和 $a[j]$($i\ne j$)的和相等,且 $a[i]$ 与 $a[j]$ 的商相等。请你计算该数组中所有符合条件的数对 $(i,j)$ 的数量。
我们可以先遍历数组 $a$,对于每个元素 $a[i]$,我们可以进行一次线性搜索,寻找数组中所有与 $a[i]$ 的和相等且和 $a[i]$ 的商相等的元素 $a[j]$。这样一来,我们就可以得到所有符合条件的数对 $(i,j)$。由于我们需要进行两次遍历,该算法的时间复杂度为 $O(n^2)$。
如果我们能够在一次遍历中找到所有符合条件的数对 $(i,j)$,那么我们的算法的时间复杂度就可以是线性的。假设 $r$ 是所有不同的商的数量,我们可以对数组 $a$ 进行一次排序,并将数组 $a$ 中的元素按照商的值进行分组。然后,对于每个分组中的元素 $a[i]$,我们需要寻找其他分组中所有与 $a[i]$ 相加为 $a[i]\times k$ 的元素,其中 $k$ 是 $a[i]$ 与其他元素之间的商。
这一算法的核心在于如何快速查找数组中某个元素。常用的查找算法有很多,如二分查找、哈希表等。对于本题而言,我们可以使用哈希表(或者 C++ 中的 unordered_map
)来加速查找。
时间复杂度为 $O(n\log n)$(排序)或 $O(n)$(哈希表),空间复杂度为 $O(n)$。
#include <iostream>
#include <vector>
#include <unordered_map>
#include <algorithm>
using namespace std;
int main() {
int n;
cin >> n;
vector<int> a(n);
// 输入数组
for (int i = 0; i < n; ++i) {
cin >> a[i];
}
// 将数组排序
sort(a.begin(), a.end());
// 分组
unordered_map<int, vector<int>> groups;
for (int i = 0; i < n; ++i) {
groups[a[i]].push_back(i);
}
int cnt = 0;
// 遍历数组,并在哈希表中查询符合条件的数对
for (int i = 0; i < n; ++i) {
for (int j : groups[a[i]]) {
if (j > i) {
cnt += groups.count(a[j]-a[i]) && find(groups[a[j]-a[i]].begin(), groups[a[j]-a[i]].end(), j) == groups[a[j]-a[i]].end();
}
}
}
cout << cnt << endl;
return 0;
}