我正在寻找一种非递归算法(最好是在C#中),它会从一组正数中生成所有可能总和的列表。
E.g。对于一组三个数字" 1,2,3"以下七笔钱是可能的:
1
2
3
1 + 2 = 3
1 + 3 = 4
2 + 3 = 5
1 + 2 + 3 = 6
最大设置大小约为50.我知道如何递归地处理这个问题,但是在处理类似问题时过去一直受到调用堆栈的限制,所以这次要避免它。
答案 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;