Algorithm 三重求和算法?

Algorithm 三重求和算法?,algorithm,big-o,asymptotic-complexity,Algorithm,Big O,Asymptotic Complexity,我们有一个带有m个正整数的数组A,有什么算法可以 如果a中有一个三元组(x,y,z),则返回true 使得A[x]+A[y]+A[z]=200 否则返回false。数组中的数字是不同的,运行时间必须为O(n) 我想出了O(n^3)。关于如何用O(n)实现这一点有什么想法吗?这被称为3SUM问题,目前还没有线性解决方案。我使用二进制搜索算法提供了一个以O(n^2)运行的伪代码: sumTriple(А[1...n]: array of integers,sum: integer): bool

我们有一个带有m个正整数的数组A,有什么算法可以

如果a中有一个三元组(x,y,z),则返回true 使得A[x]+A[y]+A[z]=200

否则返回false。数组中的数字是不同的,运行时间必须为O(n)


我想出了O(n^3)。关于如何用O(n)实现这一点有什么想法吗?

这被称为3SUM问题,目前还没有线性解决方案。我使用二进制搜索算法提供了一个以O(n^2)运行的伪代码:

sumTriple(А[1...n]: array of integers,sum: integer): bool

 sort(A)

 for i ← 1 to n-2
  j ← i+1
  k ← n

  while k > j
   if A[i]+A[j]+A[k] = sum
    print i,j,k
    return true

   else if A[i]+A[j]+A[k] > sum
    k ← k-1

   else // A[i]+A[j]+A[k] < sum
    j ← j+1

return false
sumtree(А[1…n]:整数数组,和:整数):bool
排序(A)
因为我← 1至n-2
J← i+1
K← N
当k>j时
如果A[i]+A[j]+A[k]=和
打印i,j,k
返回真值
如果A[i]+A[j]+A[k]>和
K← k-1
else//A[i]+A[j]+A[k]

您可以找到有关该问题的更多信息和详细信息

由于元素是唯一的,这归结为对O(n)中的数组进行预处理以过滤大于200的冗余元素(它们都不在三元组中)

然后,您有一个大小不大于200的数组

检查此数组中的所有三元组是
O(200^3)=O(1)
(但在常量方面可以更有效地完成)


所以,这将是O(n)uo(200^3)=O(n)

我想你可以通过位运算来解决这个问题。例如在C++ STL.

中的位集 使用3个位集,第一个位集缓存通过添加1个数字可以获取的所有数字,第二个位集缓存通过添加2个数字可以获取的所有数字,第三个位集缓存通过添加3个数字可以获取的所有数字。然后,如果有新的数字出现,您可以通过简单的位操作来维护位集

这里是一个C++代码示例:

bitset<256> bs[4];
for (int i = 0; i < 4; ++i)
    bs[i].reset();

int N, number;

cin >> N;
while (N--)
{
    cin >> number;

    bs[3] |= (bs[2] << number);
    bs[2] |= (bs[1] << number);
    if (number <= 200)
        bs[1].set(number);

    //cout << "1: " << bs[1] << endl;
    //cout << "2: " << bs[2] << endl;
    //cout << "3: " << bs[3] << endl;
}

cout << bs[3][200] << endl;
位集bs[4];
对于(int i=0;i<4;++i)
bs[i].reset();
int N,数字;
cin>>N;
而(N--)
{
cin>>数量;

我同意@amit的解决方案,但有一个问题:在我们的情况下,我们怎样才能做得更好,只是更快

这是我的解决方案,它几乎基于amit的想法,但渐近复杂性==
O(n+sum*(sum+1)/2)
,其中
n
是输入数组的长度

首先,我们需要
n
步骤来过滤输入数组,并将每个值减去和放入新数组,其中值的索引等于值。在这一步结束时,我们得到了数组,数组的大小等于和,我们可以访问
O(1)
中的任何值

最后,要找到
x,y,z
,我们只需要
sum*(sum+1)/2步

typedef struct SumATripleResult
{
    unsigned int x;
    unsigned int y;
    unsigned int z;
} SumATripleResult;

SumATripleResult sumATriple(unsigned int totalSum, unsigned int *inputArray, unsigned int n)
{
    SumATripleResult result;

    unsigned int array[totalSum];

    //Filter the input array and put each value into 'array' where array[value] = value
    for (size_t i = 0; i<n; i++)
    {
        unsigned int value = inputArray[i];

        if(value<totalSum)
        {
            array[value] = value;
        }
    }

    unsigned int x;
    unsigned int y;
    unsigned int z;

    for (size_t i = 0; i<totalSum; i++)
    {
        x = array[i];

        for (size_t j = i+1; x>0 && j<totalSum; j++)
        {
            y = array[j];

            if( y==0 || x + y >= totalSum) continue;

            unsigned int zIdx = totalSum - (x + y);

            if(zIdx == x || zIdx == y) continue;

            z = array[zIdx];

            if( z != 0)
            {
                result.x = x;
                result.y = y;
                result.z = z;
                return result;
            }
        }
    }

    //nothing found
    return result;
}

//Test
unsigned int array[] = {1, 21, 30, 12, 15, 10, 3, 5, 6, 11, 17, 31};

SumATripleResult r = sumATriple(52, array, 12);
printf("result = %d %d %d", r.x, r.y, r.y);

r = sumATriple(49, array, 12);
printf("result = %d %d %d", r.x, r.y, r.y);

r = sumATriple(32, array, 12);
printf("result = %d %d %d", r.x, r.y, r.y); 
typedef结构SumATripleResult
{
无符号整数x;
无符号整数y;
无符号整数z;
}苏门答腊结果;
sumATriple结果sumATriple(无符号整数总和、无符号整数*输入阵列、无符号整数n)
{
苏门答腊结果;
无符号整数数组[总和];
//过滤输入数组并将每个值放入“数组”,其中数组[value]=value

对于(size_t i=0;iis)值200是常量?实际上,由于元素是不同的,假设200是常量-您的算法是
O(1)
,因为数组中的元素数以200为界。@amit这是为什么?数组中可能有数十亿个不同的数字都大于200。@tobias_k所以过滤掉它们,然后执行O(200^3)=O(1)算法,我假设没有冗余元素(所以元素在[1200]范围内)如果不是这样的话,把它转换成ti很简单。是的,200常数。数组可以是任意大小,也可以是任意正数。我们只想找到3个数,当我们把它们加起来=200时,你忽略了一个重要的事实,即和有界于200,元素是唯一的。根据这个观察,有线性时间al根据他的说法,数字不是唯一的:“数组中的数字是不同的”。是的,每个数字不会重复两次。(即使没有这个假设,当总和为常数时,也可以在线性时间内完成,但这会稍微复杂一些-只需确保每个元素的添加次数不超过3次。使用大小为200的计数器数组很容易做到)筛选出的数字应大于或等于200,因为它们是正数integers@cricket_007从技术上讲,是的,您也不需要199198,但这些优化对于大O表示法来说是无关紧要的(如果有,我会优化最后一部分或从这200个元素中找到三元组)他还可以避免使用
^3
而选择
^2
,因为如果他将所有数字放入一个集合中,他可以很快看到a+B达到200后所需的数字是否也在集合中。