5

Given an array of integers A and integers N, M. I want to find all the subsets S of A where (sum(S) mod M = N). A can have multiple integers of the same value. In my case N will be in the range 0<=n<=31, M will be 32 and A will contain integers in the same range as n.

Is there any good/"fast" way to do this?

Thanks!

2 Answers2

2

It is solvable in O(2n/2 log2(2n/2)) = O(2n/2 (n/2)), with your constrains this works on C++ less than a second.

All you need is:

1) compute all possible sums of first n/2 elements of the array and put them in map<int, int> left where left[sum] = how many times sum appears at the left part of the array

2) compute all possible sums of last n/2 elements of the array and for each sum S check does map left contains value (N - S + M)%M

to find all possible sums you could use bitmasks:

for (int mask = 1; mask < pow(2, n/2); mask++) {
    int sum = 0;
    for (int i = 0; i < n/2; i++)
        if ( (int) (mask & (1<<i)) ) 
            sum += A[i];
}
Wsl_F
  • 832
  • 1
  • 7
  • 16
2

If you'd just like to count them, we can solve it in O(|A| * M) with dynamic programming. Here's an example:

A = [2, 6, 4, 3]
M = 5

    0 1 2 3 4
S = 0 0 0 0 0 // The number of subsets with sum i (mod M)

// Iterate over A (through S each time)
2   0 0 1 0 0
6   0 1 1 1 0
4   1 2 2 1 1
3   3 3 3 3 3

Python code:

A = [2, 6, 4, 3]
M = 5
S = [0 for i in range(0, M)]


for a in A:
  STemp = [0 for i in range(0, M)]
  for (i, v) in enumerate(S):
    ii = (a + i) % M
    STemp[ii] = S[ii] + v
  STemp[a % M] = STemp[a % M] + 1
  S = STemp
  
print(S)  # [3, 3, 3, 3, 3]
Rishabh Deep Singh
  • 807
  • 1
  • 12
  • 24
גלעד ברקן
  • 23,602
  • 3
  • 25
  • 61
  • 1
    Hey! i don't really know where the target sum (N) is coming from. Also could you explain the table you made, don't really get what it's saying and what you can read from it. Thanks! – Anton Andell Dec 22 '17 at 06:51
  • @AntonAndell thank you for checking it out. This is a solution to count how many subsets have sum `i` modulo M, where `i` ranges from `0` to `M-1`. So the count of subsets with sum `N` modulo `M` will be included in the final array. The table is actually one row that gets updated when processing the next element in `A`. – גלעד ברקן Dec 22 '17 at 17:03
  • @AntonAndell Each index in the row represents, as I indicated, "the number of subsets with sum `index` (mod `M`)." Can you think of how you could apply the next element to the previous row? If you need help with that, please let me know. Here's a hint: ask yourself, "for each subset represented in `S[i]` how many subsets can be generated with the next element, `a` in `A` and where will that count be placed?" considering that if we add `a` to any such subset, we will know its result mod `M`. – גלעד ברקן Dec 22 '17 at 17:03
  • Thanks that made it much clearer. However i'm trying to get the specific subsets, do you think i can extend this way of doing it to track the subsets? – Anton Andell Dec 22 '17 at 17:19
  • @AntonAndell I believe that if we save the full `|A|*M` table (rather than overwriting a single row), we can work backwards to appropriately aggregate the integers that contributed only to subsets summing to `N` modulo `M`. Implementing it might not be trivial, though, but complexity should augment only by the needed time and space to list the actual subsets. – גלעד ברקן Dec 22 '17 at 21:04
  • I think I get the algorithm pretty well know, thanks! I'll look in to working backwards and see if i can find a solution for it. – Anton Andell Dec 23 '17 at 06:25