Im looking for some help with finding subsets of array.
int[] array = { 1,2,3,5,8,10,15,23};
I have to find all subsets of an array. If sum of the subsets elements equal to any number in array then my counter increment. For example: 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();
}
I'm ok with 2-elements and 3-elements of subsets. But 4 and above I can't figured out how to solve it?
Any help would be greatly appreciated
You only need two loops to find the sum of all subsets. The outer loop is the starting point of subsets, and the inner loop is calculating the sums of all subsets from that starting point.
With the first index as starting points the subsets are 1+2
, 1+2+3
, 1+2+3+5
and so on. As you are only interested in the sum of the subsets you can just add one item after the other to get the sum of the subsets.
Then for each sum loop through the items to check for a match:
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);
I assumed that you meant continuous subsets, but from your examples it seems that you also want non-continuous subsets.
Lets's start with the correct solution:
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
That gives us 14 different subsets that sums up to an item in the set.
You can count the subsets recursively, only keeping track of the sum and number of items in subsets. You don't need the actual subsets, only to know the sum and that there are at least two items in the subset.
The subsets in a set is the first item combined with all subsets in the rest of the set, plus the subsets in the rest of the set. For example the subsets s()
of [1,2,3]
is 1,s([2,3])
and s([2,3])
.
This gives you:
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;
}
And calling it:
int[] set = { 1, 2, 3, 5, 8, 10, 15, 23 };
Console.WriteLine(CountSubsets(set, 0, 0, 0));
Output:
14
This seems a lot like homework to me. So I will answer in that spirit (i.e. rather than write the code, point you in the right direction).
First, it's not really clear what you mean by "subset". Are you talking about contiguous runs of elements from the array? Or do you literally mean treating the array as an unordered set, from which you examine every possible subset?
The latter is significantly harder than the former. So I'm going to assume the former for the moment.
Then, it seems you really have two different problems:
The latter is fairly straightforward. If you know these arrays will always be relatively short (and hopefully they will be, otherwise "find all subsets" may take awhile :) ), you can just do a linear search every time you have a new sum to look for.
Alternatively, a more semantically straightforward approach would be to create a HashSet<int>
instance once using the members of the array, and then when you want to know if the sum is in the array, just check your set.
For example:
HashSet<int> setOfValues = new HashSet<int>(array);
Then you can just write setOfValues.Contains(sum)
to check whether the value held by the variable sum
is contained in the array.
As for the first problem, it seems to me that you really should only need two loops:
Considering for a moment the alternative possibility — that you are treating the array as an unordered set — then it seems to me an obvious, if brute-force approach, would be to generate the subsets recursively.
In that approach, you would again have a loop to enumerate the subset lengths, starting with 1, up to the total length of the original set. Then, given a length, you need to pick all possible subsets.
You can do this recursively:
The easiest implementation of the above will create new copies of the current set for each level of recursion, to pass to the method when it calls itself. This way you don't have to worry about one level of recursion interfering with previous levels.
Do note that this is going to be practical only for relatively small initial sets. It won't take very large initial arrays before your computer doesn't have enough time or memory to complete the search of all possible subsets.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With