找出数组中的三元组数(i,j,k),使得A [i] + A [j] = 2 * A [k]

时间:2018-04-06 21:48:25

标签: c++ math

如何在数组中找到连音符/对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';
}

2 个答案:

答案 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]

      • 如果达到相等则增加计数

对于给定的ijk会单调增加到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

您实际上找到了ijk的3个范围,这样每个范围中的值都相等,因此您可以从相应的范围中选择任意数字。简单的组合学建议上面的公式。