我们有一组数字A = {X1,X2,...,Xn}以及确定A组元素的所有可能总和的最有效算法是什么?可能是效率相似的算法很少。我宁愿不希望他们使用非常复杂的图书馆,也不希望他们使用那种数学。
我更喜欢伪代码,Java或C ++的解决方案
PS。当我说有效时,我的意思是算法的共同效率,当然不是执行算法风格的效率。
答案 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链接以参考一些可以通过伪多项式时间算法求解的特殊情况。上述案例或其他特殊情况可能适用于您的使用。