什么是确定某些数字的所有可能总和的最有效算法

时间:2014-09-28 18:03:12

标签: algorithm

我们有一组数字A = {X1,X2,...,Xn}以及确定A组元素的所有可能总和的最有效算法是什么?可能是效率相似的算法很少。我宁愿不希望他们使用非常复杂的图书馆,也不希望他们使用那种数学。

我更喜欢伪代码,Java或C ++的解决方案

PS。当我说有效时,我的意思是算法的共同效率,当然不是执行算法风格的效率。

1 个答案:

答案 0 :(得分:1)

在设计算法之前需要考虑一些因素。我将首先对集合中的元素范围和集合的大小做一些假设。

首先让我们说数字是 A = {X1,X2,X3,...,Xn} ,它们在 Min< = Xi的范围内< = Max 。通过这个前提,最大总可能总和将是 SUM = X1 + X2 + C3 + ... + Xn

在这种情况下,我将从大小为SUM + 1的数组 possibleSums 开始。该数组分别表示特定和是否可能为0或1。因此,如果从给定集合中可以说14是可能的话,那么possibleSums [14]将具有值1,而如果假设87不可能作为来自任何子集的总和那么possibleSums [87]将为0.因为0总是可以通过选择一个空子集,所以我将从初始化 possibleSums [0] = 1 开始。

之后我遍历数组的每个元素 Xi ,并且对于每个 possibleSums [i] == 1 ,我将设置 possibleSums [i + Xi] ] = 1 。这很清楚,因为如果可以说从前面的元素可以得到13,那么通过添加下一个元素3,15也是可能的。

以下是C ++中的代码:

// Sum  = X1 + X2 + X3 + ... Xn

bool possibleSums[ Sum + 1 ];

void findAllPossibleSums( int X[ N ] )
{
  // Because in an empty subset sum is 0
  possibleSums[ 0 ] = true;

  for( int i = 0; i < N; i++ )
  {
    /* Now minimum start sum when X[ i ] is included will be X[ i ] and of course maximum sum will be SUM
    */
    for( int j = SUM; j >= X[ i ]; j-- )
    {
      // If sum = j - X[ i ] is possible then sum j is also possible
      if( possibleSums[ j - X[ i ] ] )
      {
       possibleSums[ j ] = true;
      }
    }
  }
  for( int i = 0; i < SUM; i++ )
  {
    // Print the possible sums or whatever you want
    if( possibleSums[ i ] )
      cout << i <<"\n"; 
  }
}

在最坏的情况下,上述算法的复杂性是:

O(Max * n * n)及时

空间

O(Max * n)

但是,通过使用(Max * n)位来存储possibleSums而不是数组,可以减少空间复杂性。

让我们分析一些情况的复杂性(假设使用位实现了可能的Sums):

对于Max = 100和n = 10 ^ 6,它的时间达到10 ^ 10次计算量很大。

另一种解决这个问题的方法就是暴力,我在其中调用索引i和内部的递归方法,因为有两种可能性(添加数字或保留它),我曾经添加并调用递归,然后第二次我调用递归而不添加它。这具有 O(2 ^ n)的复杂性。

问题实际上是着名的Subset Sum Problem的变体,它存在于NP-complete类问题中。请参考wiki链接以参考一些可以通过伪多项式时间算法求解的特殊情况。上述案例或其他特殊情况可能适用于您的使用。