I\'m working through an interview question that goes like:
Given an array of integers and sum, check whether any combination adds up to the sum.
If you do choose to calculate a powerset, it can be done quite easily in a functional way.
In Haskell, there is a subsequences functions which essentially returns the powerset of any set, as a list of lists.
Or you can write it yourself
powerSet :: [a] -> [[a]]
powerSet [] = [[]]
powerSet x:xs = map (:x) (powerSet xs) ++ (powerSet xs)
That sounds like a classic recursion problem. You start with the first element and consider the rest of the array; for each element, either it is picked or it isn't. The base case is when the start index is greater than the length of the array. Something like
public static bool canSum(int start, int[] array, int sum)
{
if (start >= array.Length)
return sum == 0;
return canSum(start + 1, array, sum - array[start]) || canSum(start + 1, array, sum);
}
This doesn't answer your "combination" question, but it's probably the optimal solution to the Question :P
This is the subset sum problem problem where you have to search N sums.
Subset sum has a pseudo polynomial algorithm using dynamic programming:
psuedocode from this link
Subset-Sum-Solver[S = w1,w2, . . . ,wn,B]
1 Initialize M[0..n, 0..B] everywhere False apart from M[0, 0] = True
2 for i from 1 to n
do
3 for w from 0 to B
do
4 M[i,w] = M[i − 1,w] _M[i − 1,w − wi]
(any reference outside the array returns false)
5 Output M[n,B]
where B is the sum, S is the set of numbers, n is the cardinality of S (number of elements in S), and M is a n by B matrix . This algorithm is O(nB)
In the case of the interview question, do this for each sum, and you get an algorithm that's O(nmB) where m is the number of sums that you have to test.
The question is a little ambiguous, is the array of integers used to get subsets also the same array of sums? i.e. do a subset of integers in array A also add up to one of the integers in array A? in that case, then the algorithm is O(n^2B) since n == m
I see two options:
One handy insight is to realize that the binary representation of all numbers from 0
to (2^N)-1
is actually a set of bit masks for the possible combinations out of N
distinct items. For instance, for N=3
(3 items) and thus (2^3)-1 = 7
:
0: 000 = none
1: 001 = third item
2: 010 = second item
3: 011 = second and third items
4: 100 = first item
5: 101 = first and third items
6: 110 = first and second items
7: 111 = all 3 items
This makes it very easy to loop through all possible selections in a set order (so that it's impossible to skip or double-visit any potential selection).
Some care with terminology is needed here. Combinations is used to refer to picking k
items from a set of n
items, where the order of the k
items does not matter. The related concept of picking k
items from a set of n
items, where the order of the k
items does matter, is referred to as a permutation.
What you initially talk about, however:
Given an array of integers and sum, check whether any combination adds up to the sum.
is a different thing - here there is no fixed k
: you are interested in any size subset of the original items.
The set of all subsets of a set S is called the power-set of S, and there is a very simple formula for the number of members it contains. I will leave that as an exercise - once you have worked it out, it should be relatively obvious how to enumerate through the members of a set's powerset.
(Hint: the power-set of { 1, 2 }
is { {}, { 1 }, { 2 }, { 1, 2 } }
)