Subsets having Sum between A and B

Given a set of N integers. Find how many subsets of given array have sum between A and B(inclusive). 
 

Constraints: 
1 ≤ N ≤ 34, 
-2 * 107 ≤ arri ≤ 2 * 107 
-5 * 108 ≤ A, B ≤ 5 * 108 
 

Examples: 
 

Input : S[] = { 1, -2, 3 }, A = -1, B = 2
Output : 5

Explanation:
1) 0 = 0 (the empty subset)
2) {1} = 1
3) {1, -2} = 1 + (-2) = -1
4) {-2, 3} = (-2) + 3 = 1
5) {1, -2, 3} = 1 + (-2) + 3 = 2

 

Method 1 (Brute Force): We can generate all subsets of the given numbers i.e. Power Set and find the number of subsets that would give a sum between A and B. But this will have 234 operations atmost, which is not very efficient. Hence, below is an efficient approach to solve this problem.
Method 2 (Meet In The Middle): This basically reduces time complexity from O(2N) to O(2N/2
We divide the set into two sets [0…N/2] and [(N/2 + 1)…(N-1)] and generate all subsets sums individually for the two sets which will be 2 * 217 operations. Now, what we can do is to find the combinations of these sets that would give the desired sum. This again can be done in an efficient way, sort one of the summed up set and binary search the values that will yield the sum for the particular value of the other set. Sort the second set and for each element in the first set, search for the lower bound of A – S2[i] (let say ‘low’) and upper bound of B – S2[i] 
(let say ‘high’). Subtract (high – low) to get the desired answer.
 



For e.g S = { 1, 2, -1, 0 }, A = 1, B = -1. 
After dividing S into two sets, S1 = { 1, 2 } and S2 = { -1, 0 }. 
Power set of S1 = { {0}, {1}, {2}, {1, 2} } and Power set of S2 = { {0}, {-1}, {0}, {-1, 0} } 
Subset Sum of S1 = { 0, 1, 2, 3 } and Subset Sum of S2 = { 0, -1, 0, -1 } 
Now sort the S2 { -1, -1, 0, 0 } and for every value in S1, we binary search values that would yield the desired sum. For 0 we search for (-1) – 0 = -1 for lower bound and 1 – 0 = 1 for upper bound in S2, for 1 we search for (-1) – 1 = -2 and 1 – 1 = 0 in S2 and so on. 
 

C++

filter_none

edit
close

play_arrow

link
brightness_4
code

// C++ program to find the Number of Subsets that 
// have sum between A and B
#include <bits/stdc++.h>
using namespace std;
  
/* Function to Generate all subsets of a set
   start --> Starting Index of the Set for the 
             first/second half Set
   setSize --> Number of element in half Set
   S --> Original Complete Set
   res --> Store the subsets sums */
void generateSubsets(int start, int setSize, int S[],
                                    vector<int>& res)
{
    // setSize of power set of a set with setSize
    // N is (2^n - 1)
    unsigned int pow_setSize = pow(2, setSize);
  
    // Store the sum of particular subset of set
    int sum;
  
    // Run from counter 000..0 to 111..1
    for (int counter = 0; counter < pow_setSize; counter++) {
  
        // set the sum initially to zero
        sum = 0;
  
        for (int j = 0; j < setSize; j++) {
  
            // Check if jth bit in the counter is set
            // If set then pront jth element from set
            if (counter & (1 << j))
                sum += S[j + start];
        }
  
        // Store the sum in a vector
        res.push_back(sum);
    }
}
  
int numberOfSubsets(int S[], int N, int A, int B)
{
    // Vectors to store the subsets sums
    // of two half sets individually
    vector<int> S1, S2;
  
    // Generate subset sums for the first half set
    generateSubsets(0, N / 2, S, S1);
  
    // Generate subset sums for the second half set
    if (N % 2 != 0)
        generateSubsets(N / 2, N / 2 + 1, S, S2);
    else
        generateSubsets(N / 2, N / 2, S, S2);
  
    // Sort the second half set
    sort(S2.begin(), S2.end());
  
    // Vector Iterator for S1 and S2;
    vector<int>::iterator low, high;
  
    // number of required subsets with desired Sum
    int ans = 0;
  
    for (int i = 0; i < S1.size(); i++) {
  
        // search for lower bound
        low = lower_bound(S2.begin(), S2.end(), A - S1[i]);
  
        // search for upper bound
        high = upper_bound(S2.begin(), S2.end(), B - S1[i]);
  
        // Add up to get the desired answer
        ans += (high - low);
    }
    return ans;
}
  
// Driver Program to test above functions
int main()
{
    int S[] = { 1, -2, 3 };
    int N = sizeof(S) / sizeof(S[0]);
  
    int A = -1, B = 2;
  
    // Find the number of subsets with desired Sum
    cout << numberOfSubsets(S, N, A, B) << endl;
    return 0;
}

chevron_right


Python3

filter_none

edit
close

play_arrow

link
brightness_4
code

# Python3 program to find the number of
# subsets that have sum between A and B
  
# Module for Bisection algorithms
import bisect
  
'''
Function to Generate all subsets of a set
    start --> Starting Index of the Set for the 
        first/second half Set
    setSize --> Number of element in half Set
    S --> Original Complete Set
    res --> Store the subsets sums 
'''
def generateSubsets(start, setSize, S, res):
      
    # setSize of power set of a set with setSize
    # N is (2^n - 1)
    pow_setSize = pow(2, setSize)
  
    # Store the sum of particular subset of set
    add = 0
  
    # Run from counter 000..0 to 111..1
    for counter in range(pow_setSize):
          
        # set the sum initially to zero
        add = 0
  
        for j in range(setSize):
              
            # Check if jth bit in the counter is set
            # If set then pront jth element from set
            if counter & (1 << j):
                add += S[j + start]
  
        # Store the sum in a vector
        res.append(add)
          
def numberOfSubsets(S, N, A, B):
  
    # Vectors to store the subsets sums
    # of two half sets individually
    S1 = []
    S2 = []
  
    # Generate subset sums for the first half set
    generateSubsets(0, N // 2, S, S1)
  
    # Generate subset sums for the second half set
    if (N % 2 != 0):
        generateSubsets(N // 2,
                        N // 2 + 1, S, S2)
    else:
        generateSubsets(N // 2
                        N // 2, S, S2)
  
    # Sort the second half set
    S2.sort()
  
    # Number of required subsets 
    # with desired Sum
    ans = 0
  
    for i in range(len(S1)):
  
        # Search for lower bound
        low = bisect.bisect_left(S2, A - S1[i])
  
        # Search for upper bound
        high = bisect.bisect_right(S2, B - S1[i])
  
        # Add up to get the desired answer
        ans += (high - low)
  
    return ans
  
# Driver code
if __name__=="__main__":
  
    S = [ 1, -2, 3 ]
    N = len(S)
  
    A = -1
    B = 2
  
    # Find the number of subsets
    # with desired Sum
    print(numberOfSubsets(S, N, A, B))
      
# This code is contributed by vinaylingam

chevron_right


Output: 

5

 

Time Complexity: O(2 * 2N/2), where N is the size of set.
 

Attention reader! Don’t stop learning now. Get hold of all the important DSA concepts with the DSA Self Paced Course at a student-friendly price and become industry ready.




My Personal Notes arrow_drop_up

Check out this Author's contributed articles.

If you like GeeksforGeeks and would like to contribute, you can also write an article using contribute.geeksforgeeks.org or mail your article to contribute@geeksforgeeks.org. See your article appearing on the GeeksforGeeks main page and help other Geeks.

Please Improve this article if you find anything incorrect by clicking on the "Improve Article" button below.



Improved By : Kriti Joshi 1, vinaylingam