Given an array, arr[] of size N, the task is to find the median of sums of all possible subsets of the given array.
Examples:
Input: arr = {2, 3, 3}
Output: 5
Explanation:
Non-Empty Subsets of the given array are: { {2}, {3}, {3}, {2, 3}, {2, 3}, {3, 3}, {2, 3, 3} }.
Possible sum of each subset are:
{ {2}, {3}, {3}, {5}, {5}, {6}, {8} }
Therefore, the median of all possible sum of each subset is 5.
Input: arr = {1, 2, 1}
Output: 2
Naive Approach: The simplest approach to solve this problem is to generate all possible subsets of the given array and find the sum of elements of each subset. Finally, print the median of all possible subset-sum.
Time Complexity: O(N * 2N)
Auxiliary Space: O(N * 2N)
Efficient Approach: To optimize the above approach the idea is to use Dynamic programming. Following are the relation of Dynamic programming states and the base cases:
Relation between DP states:
if j ? arr[i] then dp[i][j] = dp[i – 1][j] + dp[i – 1][j – arr[i]]
Otherwise, dp[i][j] = dp[i – 1][j]
where dp[i][j] denotes total number of ways to obtain the sum j either by selecting the ith element or not selecting the ith element.
Base case: dp[i][0] = 1
Follow the steps below to solve the problem:
- Initialize a 2D array, say DP[][] to store the above mentioned DP states.
- Fill all the dp[][] state in a bottom-up manner using the above-mentioned relation between the DP states.
- Initialize an array, say sumSub[] to store all possible sum of each subset.
- Traverse the dp[][] array and store sums of all possible subsets in the array sumSub[].
- Sort the sumSub[] array.
- Finally, print the middle element of sumSub[] array.
C++
#include <bits/stdc++.h>
using namespace std;
int findMedianOfsubSum( int arr[], int N)
{
int sum=0;
for ( int i=0; i < N; i++) {
sum += arr[i];
}
sort(arr, arr + N);
int dp[N][sum+1];
memset (dp, 0, sizeof (dp));
for ( int i=0; i < N; i++) {
dp[i][0] = 1;
}
dp[0][arr[0]] = 1;
for ( int i = 1; i < N; i++) {
for ( int j = 1; j <= sum; j++) {
if (j >= arr[i]) {
dp[i][j] = dp[i-1][j] +
dp[i-1][j-arr[i]];
}
else {
dp[i][j] = dp[i-1][j];
}
}
}
vector< int > sumSub;
for ( int j=1; j <= sum; j++) {
int M = dp[N - 1][j];
for ( int i = 1; i <= M; i++) {
sumSub.push_back(j);
}
}
int mid = sumSub[sumSub.size() / 2];
return mid;
}
int main()
{
int arr[] = { 2, 3, 3 };
int N = sizeof (arr) / sizeof (arr[0]);
cout << findMedianOfsubSum(arr, N);
return 0;
}
|
Java
import java.util.*;
class GFG{
static int findMedianOfsubSum( int arr[], int N)
{
int sum = 0 ;
for ( int i = 0 ; i < N; i++)
{
sum += arr[i];
}
Arrays.sort(arr);
int [][]dp = new int [N][sum + 1 ];
for ( int i = 0 ; i < N; i++)
{
for ( int j = 0 ; j < sum + 1 ; j++)
dp[i][j] = 0 ;
}
for ( int i = 0 ; i < N; i++)
{
dp[i][ 0 ] = 1 ;
}
dp[ 0 ][arr[ 0 ]] = 1 ;
for ( int i = 1 ; i < N; i++)
{
for ( int j = 1 ; j <= sum; j++)
{
if (j >= arr[i])
{
dp[i][j] = dp[i - 1 ][j] +
dp[i - 1 ][j - arr[i]];
}
else
{
dp[i][j] = dp[i - 1 ][j];
}
}
}
Vector<Integer> sumSub = new Vector<Integer>();
for ( int j = 1 ; j <= sum; j++)
{
int M = dp[N - 1 ][j];
for ( int i = 1 ; i <= M; i++)
{
sumSub.add(j);
}
}
int mid = sumSub.get(sumSub.size() / 2 );
return mid;
}
public static void main(String args[])
{
int arr[] = { 2 , 3 , 3 };
int N = arr.length;
System.out.print(findMedianOfsubSum(arr, N));
}
}
|
Python3
def findMedianOfsubSum(arr, N):
sum = 0
for i in range (N):
sum + = arr[i]
arr.sort(reverse = False )
dp = [[ 0 for i in range ( sum + 1 )]
for j in range (N)]
for i in range (N):
dp[i][ 0 ] = 1
dp[ 0 ][arr[ 0 ]] = 1
for i in range ( 1 , N, 1 ):
for j in range ( 1 , sum + 1 , 1 ):
if (j > = arr[i]):
dp[i][j] = (dp[i - 1 ][j] +
dp[i - 1 ][j - arr[i]])
else :
dp[i][j] = dp[i - 1 ][j]
sumSub = []
for j in range ( 1 , sum + 1 , 1 ):
M = dp[N - 1 ][j]
for i in range ( 1 , M + 1 , 1 ):
sumSub.append(j)
mid = sumSub[ len (sumSub) / / 2 ]
return mid
if __name__ = = '__main__' :
arr = [ 2 , 3 , 3 ]
N = len (arr)
print (findMedianOfsubSum(arr, N))
|
C#
using System;
using System.Collections.Generic;
class GFG{
static int findMedianOfsubSum( int [] arr, int N)
{
int sum = 0;
for ( int i = 0; i < N; i++)
{
sum += arr[i];
}
Array.Sort(arr);
int [,]dp = new int [N, sum + 1];
for ( int i = 0; i < N; i++)
{
for ( int j = 0; j < sum + 1; j++)
dp[i, j] = 0;
}
for ( int i = 0; i < N; i++)
{
dp[i, 0] = 1;
}
dp[0, arr[0]] = 1;
for ( int i = 1; i < N; i++)
{
for ( int j = 1; j <= sum; j++)
{
if (j >= arr[i])
{
dp[i, j] = dp[i - 1, j] +
dp[i - 1, j - arr[i]];
}
else
{
dp[i, j] = dp[i - 1, j];
}
}
}
List< int > sumSub = new List< int >();
for ( int j = 1; j <= sum; j++)
{
int M = dp[N - 1, j];
for ( int i = 1; i <= M; i++)
{
sumSub.Add(j);
}
}
int mid = sumSub[sumSub.Count / 2];
return mid;
}
public static void Main()
{
int [] arr = { 2, 3, 3 };
int N = arr.Length;
Console.Write(findMedianOfsubSum(arr, N));
}
}
|
Javascript
<script>
function findMedianOfsubSum(arr, N)
{
var sum = 0;
for ( var i = 0; i < N; i++)
{
sum += arr[i];
}
arr.sort((a, b) => a - b)
var dp = Array.from(
Array(N), () => Array(sum + 1).fill(0));
for ( var i = 0; i < N; i++)
{
dp[i][0] = 1;
}
dp[0][arr[0]] = 1;
for ( var i = 1; i < N; i++)
{
for ( var j = 1; j <= sum; j++)
{
if (j >= arr[i])
{
dp[i][j] = dp[i - 1][j] +
dp[i - 1][j - arr[i]];
}
else
{
dp[i][j] = dp[i - 1][j];
}
}
}
var sumSub = [];
for ( var j = 1; j <= sum; j++)
{
var M = dp[N - 1][j];
for ( var i = 1; i <= M; i++)
{
sumSub.push(j);
}
}
var mid = sumSub[parseInt(sumSub.length / 2)];
return mid;
}
var arr = [ 2, 3, 3 ];
var N = arr.length
document.write(findMedianOfsubSum(arr, N));
</script>
|
Time Complexity: O(N*Sum), where N is the size of the array and Sum is the sum of all the elements in the array.
Auxiliary Space: O(N*Sum). We use a 2-dimensional array of size N*Sum to store the intermediate results.
Efficient Approach : using array instead of 2d matrix to optimize space complexity
In previous code we can se that dp[i][j] is dependent upon dp[i-1][j-1] or dp[i][j-1] so we can assume that dp[i-1] is previous row and dp[i] is current row.
Implementations Steps :
- Create two vectors prev and curr each of size sum+1, where sum is the sum of all elements of arr. These vectors are used to store the total number of ways to form the sum j using the elements of arr.
- Initialize them with base cases.
- Now In previous code change dp[i] to curr and change dp[i-1] to prev to keep track only of the two main rows.
- After every iteration update previous row to current row to iterate further.
Implementation :
C++
#include <bits/stdc++.h>
using namespace std;
int findMedianOfsubSum( int arr[], int N)
{
int sum=0;
for ( int i=0; i < N; i++) {
sum += arr[i];
}
sort(arr, arr + N);
vector< int >prev(sum+1 , 0);
vector< int >curr(sum+1 , 0);
for ( int i=0; i < N; i++) {
prev[0] = 1;
}
prev[arr[0]] = 1;
curr[arr[0]] = 1;
for ( int i = 1; i < N; i++) {
for ( int j = 1; j <= sum; j++) {
if (j >= arr[i]) {
curr[j] = prev[j] + prev[j-arr[i]];
}
else {
curr[j] = prev[j];
}
}
prev = curr;
}
vector< int > sumSub;
for ( int j=1; j <= sum; j++) {
int M = curr[j];
for ( int i = 1; i <= M; i++) {
sumSub.push_back(j);
}
}
int mid = sumSub[sumSub.size() / 2];
return mid;
}
int main()
{
int arr[] = { 2, 3, 3 };
int N = sizeof (arr) / sizeof (arr[0]);
cout << findMedianOfsubSum(arr, N);
return 0;
}
|
Java
import java.util.Arrays;
import java.util.ArrayList;
public class MedianOfSubSum {
static int findMedianOfSubSum( int [] arr, int N) {
int sum = 0 ;
for ( int i = 0 ; i < N; i++) {
sum += arr[i];
}
Arrays.sort(arr);
int [] prev = new int [sum + 1 ];
int [] curr = new int [sum + 1 ];
for ( int i = 0 ; i < N; i++) {
prev[ 0 ] = 1 ;
}
prev[arr[ 0 ]] = 1 ;
curr[arr[ 0 ]] = 1 ;
for ( int i = 1 ; i < N; i++) {
for ( int j = 1 ; j <= sum; j++) {
if (j >= arr[i]) {
curr[j] = prev[j] + prev[j - arr[i]];
} else {
curr[j] = prev[j];
}
}
prev = curr.clone();
}
ArrayList<Integer> sumSub = new ArrayList<>();
for ( int j = 1 ; j <= sum; j++) {
int M = curr[j];
for ( int i = 1 ; i <= M; i++) {
sumSub.add(j);
}
}
int mid = sumSub.get(sumSub.size() / 2 );
return mid;
}
public static void main(String[] args) {
int [] arr = { 2 , 3 , 3 };
int N = arr.length;
System.out.println(findMedianOfSubSum(arr, N));
}
}
|
Python3
import math
def findMedianOfsubSum(arr, N):
sum = 0
for i in range (N):
sum + = arr[i]
arr.sort()
prev = [ 0 ] * ( sum + 1 )
curr = [ 0 ] * ( sum + 1 )
for i in range (N):
prev[ 0 ] = 1
prev[arr[ 0 ]] = 1
curr[arr[ 0 ]] = 1
for i in range ( 1 , N):
for j in range ( 1 , sum + 1 ):
if j > = arr[i]:
curr[j] = prev[j] + prev[j - arr[i]]
else :
curr[j] = prev[j]
prev = curr[:]
sumSub = []
for j in range ( 1 , sum + 1 ):
M = curr[j]
for i in range ( 1 , M + 1 ):
sumSub.append(j)
mid = sumSub[math.floor( len (sumSub) / 2 )]
return mid
arr = [ 2 , 3 , 3 ]
N = len (arr)
print (findMedianOfsubSum(arr, N))
|
C#
using System;
using System.Collections.Generic;
public class MedianOfSubSum
{
static int findMedianOfSubSum( int [] arr, int N)
{
int sum = 0;
for ( int i = 0; i < N; i++)
{
sum += arr[i];
}
Array.Sort(arr);
int [] prev = new int [sum + 1];
int [] curr = new int [sum + 1];
for ( int i = 0; i < N; i++)
{
prev[0] = 1;
}
prev[arr[0]] = 1;
curr[arr[0]] = 1;
for ( int i = 1; i < N; i++)
{
for ( int j = 1; j <= sum; j++)
{
if (j >= arr[i])
{
curr[j] = prev[j] + prev[j - arr[i]];
}
else
{
curr[j] = prev[j];
}
}
prev = ( int [])curr.Clone();
}
List< int > sumSub = new List< int >();
for ( int j = 1; j <= sum; j++)
{
int M = curr[j];
for ( int i = 1; i <= M; i++)
{
sumSub.Add(j);
}
}
int mid = sumSub[sumSub.Count / 2];
return mid;
}
public static void Main( string [] args)
{
int [] arr = { 2, 3, 3 };
int N = arr.Length;
Console.WriteLine(findMedianOfSubSum(arr, N));
}
}
|
Javascript
function findMedianOfsubSum(arr, N) {
let sum = 0;
for (let i = 0; i < N; i++) {
sum += arr[i];
}
arr.sort((a, b) => a - b);
let prev = new Array(sum + 1).fill(0);
let curr = new Array(sum + 1).fill(0);
for (let i = 0; i < N; i++) {
prev[0] = 1;
}
prev[arr[0]] = 1;
curr[arr[0]] = 1;
for (let i = 1; i < N; i++) {
for (let j = 1; j <= sum; j++) {
if (j >= arr[i]) {
curr[j] = prev[j] + prev[j - arr[i]];
} else {
curr[j] = prev[j];
}
}
prev = [...curr];
}
let sumSub = [];
for (let j = 1; j <= sum; j++) {
let M = curr[j];
for (let i = 1; i <= M; i++) {
sumSub.push(j);
}
}
let mid = sumSub[Math.floor(sumSub.length / 2)];
return mid;
}
let arr = [2, 3, 3];
let N = arr.length;
console.log(findMedianOfsubSum(arr, N));
|
Time Complexity: O(N*Sum)
Auxiliary Space: O(Sum)