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.
Implementation:
// 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 print 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;
} |
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Scanner;
import java.util.function.BiPredicate;
// Java program to find the Number of Subsets that // have sum between A and B public class Main
{ /* 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 */
private static void generateSubsetSumsRecur( int [] arr, int st, int end, int index, int runningSum, List<Integer> sums) {
if (index == end+ 1 ) {
sums.add(runningSum);
return ;
}
generateSubsetSumsRecur(arr, st, end, index+ 1 , runningSum+arr[index], sums);
generateSubsetSumsRecur(arr, st, end, index+ 1 , runningSum, sums);
}
private static long numberOfSubsets( int arr[], int n, int a, int b) {
// Generate subset sums for the first half set
List<Integer> sums = new ArrayList<>();
generateSubsetSumsRecur(arr, 0 , n/ 2 , 0 , 0 , sums);
Integer[] firstSubsetSums= sums.toArray( new Integer[ 0 ]);
// Generate subset sums for the second half set
List<Integer> sums2 = new ArrayList<>();
generateSubsetSumsRecur(arr, n/ 2 + 1 , n- 1 , n/ 2 + 1 , 0 , sums2);
Integer[] secondSubsetSums= sums2.toArray( new Integer[ 0 ]);
// Sort the second half set
Arrays.sort(secondSubsetSums);
long count = 0 ;
for ( int i= 0 ; i<firstSubsetSums.length; i++) {
int p = findLastIdxWithFalsePredicate(secondSubsetSums,
a-firstSubsetSums[i],
(sum, mark)->sum>=mark);
int q = findLastIdxWithFalsePredicate(secondSubsetSums,
b-firstSubsetSums[i],
(sum, mark)->sum>mark);
count += (q-p);
}
return count;
}
private static int findLastIdxWithFalsePredicate(Integer[] sums,
int val,
BiPredicate<Integer, Integer> pred) {
int min = 0 ;
int max = sums.length- 1 ;
while (min<max) {
int mid = min + (max-min+ 1 )/ 2 ;
if (pred.test(sums[mid], val)) {
max = mid- 1 ;
} else {
min = mid;
}
}
if (pred.test(sums[min], val))
return - 1 ;
return min;
}
// Driver code
public static void main(String args[])
{
int N = 3 ;
int A = - 1 ;
int B = 2 ;
int arr[] = { 1 , - 2 , 3 };
System.out.println(numberOfSubsets(arr, N, A, B));
}
} // This code is contributed by Manu Pathria |
# 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 print 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 |
// JavaScript program to find the Number of Subsets that // have sum between A and B // 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 function generateSubsets(start, setSize, S, res) {
// setSize of power set of a set with setSize N is (2^n - 1)
const pow_setSize = Math.pow(2, setSize);
// Store the sum of particular subset of set
let sum = 0;
// Run from counter 000..0 to 111..1
for (let counter = 0; counter < pow_setSize; counter++) {
// set the sum initially to zero
sum = 0;
for (let j = 0; j < setSize; j++) {
// Check if jth bit in the counter is set
// If set then add jth element from set to sum
if (counter & (1 << j)) sum += S[j + start];
}
// Store the sum in a vector
res.push(sum);
}
} function numberOfSubsets(S, N, A, B) {
// Vectors to store the subsets sums
// of two half sets individually
const S1 = [];
const S2 = [];
// Generate subset sums for the first half set
generateSubsets(0, Math.floor(N / 2), S, S1);
// Generate subset sums for the second half set
if (N % 2 !== 0) generateSubsets(Math.floor(N / 2), Math.floor(N / 2) + 1, S, S2);
else generateSubsets(Math.floor(N / 2), Math.floor(N / 2), S, S2);
// Sort the second half set
S2.sort((a, b) => a - b);
// Vector Iterator for S1 and S2;
let low;
let high;
// number of required subsets with desired Sum
let ans = 0;
for (let i = 0; i < S1.length; i++) {
// search for lower bound
low = S2.findIndex((num) => num >= A - S1[i]);
// search for upper bound
high = S2.findIndex((num) => num > B - S1[i]);
// Add up to get the desired answer
ans += high - low;
}
return ans;
} // Driver Program to test above functions const S = [1, -2, 3]; const N = S.length; const A = -1; const B = 2; // Find the number of subsets with desired Sum console.log(numberOfSubsets(S, N, A, B)); // This code is contributed by rutikbhosale |
// C# program to find the Number of Subsets that // have sum between A and B using System;
using System.Collections.Generic;
using System.Linq;
class Program
{ static void Main( string [] args)
{
int [] S = { 1, -2, 3 };
int N = S.Length;
int A = -1, B = 2;
// Find the number of subsets with desired sum
Console.WriteLine(numberOfSubsets(S, N, A, B));
}
// 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
static void generateSubsets( int start, int setSize, int [] S,
List< int > res)
{
// setSize of power set of a set with setSize
// N is (2^n - 1)
int pow_setSize = ( int )Math.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 print jth element from set
if ((counter & (1 << j)) != 0)
sum += S[j + start];
}
// Store the sum in a list
res.Add(sum);
}
}
static int numberOfSubsets( int [] S, int N, int A, int B)
{
// Lists to store the subsets sums
// of two half sets individually
List< int > S1 = new List< int >();
List< int > S2 = new List< int >();
// 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
int ans = 0;
for ( int i = 0; i < S1.Count; i++)
{
// search for lower bound
int low = S2.BinarySearch(A - S1[i]);
if (low < 0) low = ~low;
// search for upper bound
int high = S2.BinarySearch(B - S1[i]);
if (high < 0) high = ~high - 1;
// Add up to get the desired answer
ans += (high - low + 1);
}
return ans;
}
} // Contributed by adityahsarmadev01 |
5
Time Complexity: O(2 * 2N/2), where N is the size of set.