如何在数组中找到连音符/对i,j,k的数目,使得a [i] + a [j] = 2 * a [k]。由于n <= 10 ^ 5,复杂度应为O(n * logn)或O(n)。
编辑2(重要):abs(a [i])&lt; = 10 ^ 3。
编辑: i,j,k必须都是不同的。
这是我的代码,但它太慢了,它的复杂性为O(n ^ 2 logn)。
#include <bits/stdc++.h>
using namespace std;
int binarna(vector<int> a, int k){
int n = a.size();
int low = 0, high = n - 1;
bool b = false;
int mid;
while(low <= high){
mid = (low + high) / 2;
if (a[mid] == k){
b = true;
break;
}
if (k < a[mid])
high = mid - 1;
else
low = mid + 1;
}
if (b)
return mid;
else
return -1;
}
int main()
{
int n;
cin >> n;
vector<int> a(n);
for (auto& i : a)
cin >> i;
sort(a.begin(), a.end());
int sol = 0;
for (int i = 0; i < n - 1; ++i){
for (int j = i + 1; j < n; ++j){
if ((a[i] + a[j]) % 2)
continue;
int k = (a[i] + a[j]) / 2;
if (binarna(a, k) != -1)
++sol;
}
}
cout << sol << '\n';
}
答案 0 :(得分:0)
复杂性可能比O(N²)
更好,因为在元素形成单个算术级数的情况下,所有(i, j)
对j-i
甚至都有一个合适的元素中间和计数是O(N²)
*。
O(N²)
解决方案如下:
逐渐对数组进行排序;
i
的,
设置k=i
和每j>i
,
将k
增加到2 A[k] >= A[i] + A[j]
如果达到相等则增加计数
对于给定的i
,j
和k
会单调增加到N
,因此总操作数为O(N-i)
。这证明了全局行为O(N²)
,这是最佳的。
*这里有一点微妙之处,因为你可能会声称与论证相矛盾:&#34;我们可以确定数组在时间O(N)
中形成一个算术序列,并从此计算出一个单一的计数去&#34;
但是如果不是单个算术序列,我们有两个长度为N/2
的算术序列,即使它们交织在一起,计数的二次行为仍然存在。并且至少有N
种方法可以交织两个算术序列。
如果元素的范围远小于它们的数量,则通过直方图压缩数据是有利的。
三重检测算法简化了一点,因为k
系统地(i+j)/2
。现在,每个三元组都计入Hi.Hk.Hj
而不是1
。复杂度为O(M²)
,其中M
是直方图的大小。
答案 1 :(得分:0)
让我们调用D
- 数组中不同值的总数。如果abs(a[i]) <= 10^3
,则数组中的值不能超过2*10^3
个不同的值。这意味着如果你有点聪明,你的算法的复杂性变得最小O(D^2*log(D))
和O(N*log(N))
,这远远好于O(N^2*log(N))
,如果你使用Yves建议的智能算法,你会得到至少O(D^2*log(D))
和O(N*log(N))
。
显然O(N*log(N))
来自排序,你无法避免,但即使N = 10^5
也没关系。那么如何在算法的主要部分中将N
减少到D
?这并不难。您需要的是将int
数组替换为元组数组(value, count)
(我们称之为B
)。通过在对原始数组进行排序后扫描来获得这样的数组很容易。此新数组的大小为D
(而不是N
)。现在您将算法或Yves改进算法应用于此数组,但每次找到三元组(i,j,k)
时
2*B[k].value == B[i].value + B[j].value
您将总计数器增加
totalCount += B[k].count * B[i].count * B[j].count
为什么会这样?考虑原始排序的数组。当你发现三元组(i,j,k)
时
2*A[k].value == A[i].value + A[j].value
您实际上找到了i
,j
和k
的3个范围,这样每个范围中的值都相等,因此您可以从相应的范围中选择任意数字。简单的组合学建议上面的公式。