非递归算法,用于根据数字集确定所有可能的总和

时间:2015-03-01 10:16:41

标签: c# algorithm math recursion set

我正在寻找一种非递归算法(最好是在C#中),它会从一组正数中生成所有可能总和的列表。

E.g。对于一组三个数字" 1,2,3"以下七笔钱是可能的:

1

2

3

1 + 2 = 3

1 + 3 = 4

2 + 3 = 5

1 + 2 + 3 = 6

最大设置大小约为50.我知道如何递归地处理这个问题,但是在处理类似问题时过去一直受到调用堆栈的限制,所以这次要避免它。

3 个答案:

答案 0 :(得分:5)

如果您只需要所有可能的金额,那么您可以使用此功能。

public static IEnumerable<int> GetSums(List<int> list)
{
    return from m in Enumerable.Range(0, 1 << list.Count)
           select
               (from i in Enumerable.Range(0, list.Count)
               where (m & (1 << i)) != 0
               select list[i]).Sum();
}

然后,就这样称呼它:

var result = GetSums(myList).ToList();

其他信息

您还可以使用此方法生成组合(source)

public static IEnumerable<IEnumerable<T>> GetPowerSet<T>(List<T> list)
{
    return from m in Enumerable.Range(0, 1 << list.Count)
           select
               from i in Enumerable.Range(0, list.Count)
               where (m & (1 << i)) != 0
               select list[i];
}

Sum()命名空间的System.Linq方法的帮助下找到所有组合的总和:

var result = GetPowerSet(myList).Select(x => x.Sum()).ToList();

答案 1 :(得分:4)

子集的和与子集直接对应,子集也与二进制序列直接对应。如果您的集合中有五个项目,则需要迭代从00000到11111的所有位序列。等效地,您希望从0迭代到2 ^ 5-1。如果某个位设置为1,则应将该值包含在总和中。所以,像这样:

for i = 0 to 2^n-1
  sum = 0
  for j = 0 to n - 1
    if i & (1 << j) then 
      sum += items[j]
  yield return sum

显然,这是伪代码,并且不会处理大于i使用的位数的n值,但这将是一个很长的迭代。这至少应该让你开始。

答案 2 :(得分:0)

如果所有数字的总和受可靠值限制,那么DP解决方案存在复杂度O(N * MaxSum),否则存在O(2 ^ N)个可能的总和。

DP解决方案(Delphi):

procedure GenerateAllSums(const A: array of Integer);
var
  ASums: array of Boolean;
  S, i, j: Integer;
begin
  //find maximal possible sum
  S := 0;
  for i := 0 to High(A) do
    S := S + A[i];
  //make array for possible sums
  SetLength(ASums, S + 1);
  ASums[0] := True; // all others - false

  for i := 0 to High(A) do
    for j := S - A[i] downto 0 do
      if ASums[j] then
        ASums[j + A[i]] := True;
  //Now 'True' elements of ASums denote possible sum values
end;