C# 数组和';s子集

C# 数组和';s子集,c#,arrays,sum,subset,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[] 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();
    }
publicstaticvoidmain(字符串[]args)
{
int[]数组={1,2,3,5,8,10,15,23};
int arrayLength=array.Count();
整数和=0;
int subsetCount=0;
对于(int i=0;i
我对子集的2-元素和3-元素没有意见。但是4级以上我就不知道怎么解决了


任何帮助都将不胜感激

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

以第一个索引为起点,子集为
1+2
1+2+3
1+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);
这就给了我们14个不同的子集,这些子集加起来就是集合中的一个项

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

集合中的子集是集合其余部分的所有子集加上集合其余部分的子集的第一项组合。例如
[1,2,3]
的子集
s()
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;
}
输出:

14

这对我来说很像家庭作业。因此,我将本着这种精神回答(即,不是编写代码,而是为您指出正确的方向)

首先,不太清楚“子集”是什么意思。您是说数组中的元素连续运行吗?或者你的字面意思是把数组当作一个无序的集合,从中检查每个可能的子集

后者要比前者困难得多。所以我现在假设前者

那么,你似乎真的有两个不同的问题:

  • 找到数组的所有子集并对每个子集求和
  • 对于给定的和,确定它是否在数组中
后者相当简单。如果您知道这些数组总是相对较短的(希望它们会相对较短,否则“查找所有子集”可能需要一段时间:),那么您可以在每次查找新的和时进行线性搜索

或者,在语义上更直接的方法是使用数组的成员创建一个
HashSet
实例,然后当您想知道和是否在数组中时,只需检查集合

例如:

HashSet<int> setOfValues = new HashSet<int>(array);
HashSet setOfValues=新的HashSet(数组);
然后您可以只写
setOfValues.Contains(sum)
来检查变量
sum
所持有的值是否包含在数组中

至于第一个问题,在我看来,您实际上只需要两个循环:

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

考虑一下另一种可能性——将数组视为无序集——在我看来,一种显而易见的方法(如果是蛮力方法的话)是递归生成子集

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

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

  • 给定一个集合,迭代当前集合的元素(传递给递归方法)。当前元素是当前子集的新元素
  • 如果当前子集的长度正确,则求和并与原始集进行比较
  • 否则,从当前集合中删除当前元素并递归
上述最简单的实现将为每个递归级别创建当前集的新副本,以便在方法调用自身时传递给该方法。这样,您就不必担心一个级别的递归会干扰以前的级别

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

使用一点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);
int[]数组={1,2,3,5,8,10,15,23};
变量子集=新列表();
int计数器=0;
for(int i=0;iHashSet<int> setOfValues = new HashSet<int>(array);
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);
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) };
{  } 
{ 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();