Largest subset of Array having sum at least 0

Given an array arr[] that contains N integers, the task is to find the largest subset having sum at least 0.

Examples:

Input: arr[] = {5, -7, 0, -5, -3, -1}
Output: 4
Explanation: The largest subset that can be selected is {5, 0, -3, -1}. It has size 4

Input: arr[] = {1, -4, -2, -3}
Output: 1

Naive Approach: The basic idea to solve the problem is by using Recursion based on the following idea:

At every index, there are two choices, either select that element or not. If sum is becoming negative then don’t pick it otherwise pick it. And from every recursion return the size of the largest possible subset between the two choices.

Follow the steps mentioned below:

  • Use a recursive function and for each index there are two choices either select that element or not.
  • Avoid selecting that element, whose value make the sum negative.
  • Return the count of maximum picked elements out of both choices.
  • The maximum among all of these is the required subset size.

Below is the implementation of the above approach:

C++

 

#include <bits/stdc++.h>

using namespace std;

 

int pick_max_elements(int pos, int sum,

                      int n, int arr[])

{

 

    

    

    if (pos == n)

        return 0;

 

    int taken = INT_MIN;

 

    

    if (sum + arr[pos] >= 0)

        taken = 1

                + pick_max_elements(pos + 1,

                                    sum + arr[pos],

                                    n, arr);

 

    int not_taken

        = pick_max_elements(pos + 1,

                            sum, n, arr);

 

    

    return max(taken, not_taken);

}

 

int main()

{

    int arr[] = { 1, -4, -2, -3 };

    int N = sizeof(arr) / sizeof(arr[0]);

 

    

    

    cout << pick_max_elements(0, 0, N, arr);

    return 0;

}

Time Complexity: O( 2N)
Auxiliary Space: O(N)

Efficient Approach: The efficient approach is using multiset based on the following idea:

Traverse from start of array and if at any index the sum till now becomes negative then erase the minimum element till current index from the subset. This will increase the subset sum.
To efficacy find the minimum multiset is used.

Follow the illustration given below for a better understanding.

Illustration:

Consider the array arr[] = {1, -4, -2, -3}

multiset s,

-> Insert arr[0] in s. s = {1}. sum = sum + arr[0] = 1

-> Insert arr[1] in s. s = { -4, 1 }. sum = sum + arr[1] = -3
-> Remove the smallest element (ie -4). sum = -3 – (-4) = 1.

-> Insert arr[2] in s. s = { -2, 1 }. sum = sum + arr[2] = -1
-> Remove the smallest element (ie -2). sum = -1 – (-2) = 1.

-> Insert arr[3] in s. s = { -3, 1 }. sum = sum + arr[1] = -2
-> Remove the smallest element (ie is -3). sum = -2 – (-3) = 1.

Total 1 element in the subset

Follow the below steps to solve this problem:

  • Iterate from i = 0 to N
    • Increment the count
    • Add the current element to the subset sum.
    • Insert arr[i] into the set.
    • If sum becomes negative then subtract the smallest value from the set and also remove the smallest element from the set
    • Decrement the count
  • Return the final count.

Below is the implementation of the above approach:

C++

 

#include <bits/stdc++.h>

using namespace std;

 

int pick_max_elements(int arr[], int n)

{

    int cnt = 0, sum = 0;

 

    

    multiset<int> s;

 

    for (int i = 0; i < n; i++) {

        sum += arr[i];

 

        

        

        cnt++;

        s.insert(arr[i]);

        if (sum < 0) {

            sum = sum - *s.begin();

 

            

            

            s.erase(s.begin());

 

            

            

            cnt--;

        }

    }

    return cnt;

}

 

int main()

{

    int arr[] = { 1, -4, -2, -3 };

 

    

    int N = sizeof(arr) / sizeof(arr[0]);

 

    

    

    cout << pick_max_elements(arr, N);

    return 0;

}

Time complexity: O( N * log N )
Auxiliary Space: O(N )

Leave a Comment