数组子集的总和

时间:2015-09-15 00:07:10

标签: c# arrays sum subset

我正在寻找一些寻找阵列子集的帮助。

int[] array = { 1,2,3,5,8,10,15,23};

我必须找到数组的所有子集。如果子集元素的总和等于数组中的任何数字,那么我的计数器递增。例如:1 + 2 = 3,2 + 3 = 5,5 + 8 + 10 = 23,1 + 2 + 5 = 8,2 + 3 + 8 + 10 = 23

public static void Main(string[] args)
    {
        int[] array = { 1, 2, 3, 5, 8, 10, 15, 23 };
        int arrayLength = array.Count();
        int sum = 0;
        int subsetCount = 0;

        for (int i = 0; i < arrayLength; i++)
        {
            for (int j = i + 1; j < arrayLength; j++)
            {
                sum = array[i] + array[j];

                for (int m = j + 1; m < arrayLength; m++)
                {
                    for (int k = 0; k < arrayLength; k++)
                    {
                        if (array[k] == sum)
                        {
                            subsetCount++;
                        }
                    }
                    sum = array[i] + array[j] + array[m];
                }
            }
        }
        Console.WriteLine(subsetCount);
        Console.ReadLine();
    }

我可以使用2个元素和3个元素的子集。但4岁以上我无法弄清楚如何解决它?

非常感谢任何帮助

4 个答案:

答案 0 :(得分:3)

您只需要两个循环即可找到所有子集的总和。外循环是子集的起始点,内循环计算从该起点开始的所有子集的总和。

以第一个索引作为起点,子集为1+21+2+31+2+3+5,依此类推。由于您只对子集的总和感兴趣,您可以只添加一个项目以获得子集的总和。

然后对每个项目的总和循环检查匹配:

int[] array = { 1, 2, 3, 5, 8, 10, 15, 23 };
int subsetCount = 0;
for (int i = 0; i < array.Length; i++) {
  int sum = array[i];
  for (int j = i + 1; j < array.Length; j++) {
    sum += array[j];
    for (int k = 0; k < array.Length; k++) {
      if (array[k] == sum) {
        subsetCount++;
      }
    }
  }
}
Console.WriteLine(subsetCount);

编辑:

我认为你的意思是连续的子集,但是从你的例子来看,你似乎也想要不连续的子集。

让我们从正确的解决方案开始:

23 = 15+8, 15+5+3, 15+5+2+1, 10+8+5, 10+8+3+2
15 = 10+5, 10+3+2, 8+5+2
10 = 8+2, 5+3+2
 8 = 5+3, 5+2+1
 5 = 3+2
 3 = 2+1

这为我们提供了14个不同的子集,这些子集总计了集合中的项目。

您可以递归计算子集,仅跟踪子集中项目的总和和数量。您不需要实际的子集,只需知道总和,并且子集中至少有两个项目。

集合中的子集是与集合其余部分中的所有子集相结合的第一个项目,以及集合其余部分中的子集。例如,s()的子集[1,2,3]1,s([2,3])s([2,3])

这会给你:

public static int CountSubsets(int[] arr, int start, int len, int sum) {
  int cnt = 0;
  if (start < arr.Length) {
    if (len >= 1 && arr.Contains(sum + arr[start])) cnt++;
    cnt += CountSubsets(arr, start + 1, len + 1, sum + arr[start]);
    cnt += CountSubsets(arr, start + 1, len, sum);
  }
  return cnt;
}

并称之为:

int[] set = { 1, 2, 3, 5, 8, 10, 15, 23 };
Console.WriteLine(CountSubsets(set, 0, 0, 0));

输出:

14

答案 1 :(得分:3)

这似乎很像我的作业。所以我会以这种精神回答(即不是编写代码,而是指向正确的方向)。

首先,它并不是很清楚你的意思是什么?&sub;&#34;。你在谈论阵列中连续的元素运行吗?或者你的意思是将数组视为无序集,从中检查每个可能的子集?

后者比前者强硬得多。所以我现在要承担前者。

然后,你似乎真的有两个不同的问题:

  • 查找数组的所有子集并将每个子集相加
  • 对于给定的总和,确定它是否在数组

后者相当简单。如果你知道这些数组将总是相对较短(并且希望它们将是,否则&#34;找到所有子集&#34;可能需要一段时间:)),你可以在每次有新的总和时进行线性搜索寻找。

或者,一种语义更直接的方法是使用数组成员创建一个HashSet<int>实例,然后当你想知道总和是否在数组中时,只需检查你的集合。 / p>

例如:

HashSet<int> setOfValues = new HashSet<int>(array);

然后你可以写setOfValues.Contains(sum)来检查变量sum所包含的值是否包含在数组中。

至于第一个问题,在我看来你真的应该只需要两个循环:

  • 循环迭代子集的第一个元素的索引。即您需要枚举所有子集,首先从以元素0开头的所有子集开始,然后以所有以元素1开头的子集开始,依此类推。
  • 迭代子集长度的循环。即确定了当前子集组的起始索引后,现在要查找所有实际子集:第一个具有长度1,第二个具有长度2,依此类推,直到最大可能长度(即数组的长度)减去当前基于0的起始索引值。)


暂时考虑另一种可能性 - 你将数组视为无序集合 - 然而在我看来,如果是暴力方法,则显然会以递归方式生成子集。

在该方法中,您将再次有一个循环来枚举子集长度,从1开始,直到原始集合的总长度。然后,给定长度,您需要选择所有可能的子集。

你可以递归地执行此操作:

  • 给定一个集合,迭代当前集合的元素(传入您的递归方法)。当前元素是当前子集的新元素。
  • 如果您当前的子集现在是正确的长度,请将其相加并与原始集合进行比较。
  • 否则,从当前集中删除当前元素并递归。

上面最简单的实现将为每个递归级别创建当前集的新副本,以便在调用自身时传递给该方法。这样您就不必担心一级递归会干扰先前的级别。

请注意,这仅适用于相对较小的初始集。在您的计算机没有足够的时间或内存来完成所有可能子集的搜索之前,它不会占用非常大的初始数组。

答案 2 :(得分:3)

首先,你需要一个能返回所有子集的方法。

Func<IEnumerable<int>, IEnumerable<IEnumerable<int>>> getAllSubsets = null;
getAllSubsets = xs =>
    (xs == null || !xs.Any())
        ? Enumerable.Empty<IEnumerable<int>>()
        :  xs.Skip(1).Any()
            ? getAllSubsets(xs.Skip(1))
                .SelectMany(ys => new [] { ys, xs.Take(1).Concat(ys) })
            : new [] { Enumerable.Empty<int>(), xs.Take(1) };

所以给定getAllSubsets(new[] { 1, 2, 3 })我得到:

{  } 
{ 1 } 
{ 2 } 
{ 1, 2 } 
{ 3 } 
{ 1, 3 } 
{ 2, 3 } 
{ 1, 2, 3 } 

现在,您可以轻松计算出您想要的结果。

int[] array = { 1,2,3,5,8,10,15,23};

var result =
    getAllSubsets(array)
        .Where(ss => array.Contains(ss.Sum()))
        .Count();

我得到22

答案 3 :(得分:0)

使用一点Linq:

int[] array = {1, 2, 3, 5, 8, 10, 15, 23};
var subsets = new List<IEnumerable<int>>();
int counter = 0;

for (int i = 0; i < array.Length; i++)
{
    for (int j = 2; j < array.Length - i; j++)
    {
        if (array.Contains(array.Skip(i).Take(j).ToList().Sum()))
        {
            counter++;
        }
    }
}

Console.WriteLine("Number of subsets:" + counter);

给你:

  

子集数量:5