Open In App

Minimum number of operations required to make all the elements positive

Last Updated : 04 Apr, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array A[] of length N. You can apply the below operation:

  • Choose an index i such that (i+1) element exists. After that choose any number X (positive or negative). Then subtract X from the ith element and add it into (i+1)th element.

The task is to find the minimum number of operations required to make all array elements positive. If not possible output -1.

Examples:

Input: N = 3, A[] = {-3, 2, 1}
Output: 2
Explanation: The performed operations are as below:

  • First operation: Choose i = 2 and X = -1. Then update A2 and A3 as 2-(-1)=3 and 1+(-1)=0 respectively. Then, updated A[] is {-3, 3, 0}
  • Second operation: Choose i = 1 and X = -3. Then update A1 and A2 as -3-(-3) = 0 and 3+(-3)=0 respectively. Then, updated A[] is {0, 0, 0}. Now all the elements are >= 0. Therefore, minimum number of operations are 2.

Input: N = 2, A[] = {1, -2}
Output: -1
Explanation: It can be verified that using given operation it is not possible to make all Ai >=0.

Approach: Implement the idea below to solve the problem

The problem can be solved using Prefix Sums and LIS (Longest Increasing Subsequence) Concept. Let us see the significance of both. The main approach for solving the problem is to calculate N - LIS[N-1], where LIS[N-1] is the length of the longest increasing subsequence of the Prefix sum array, and N - LIS[N-1] is the minimum number of elements that need to be removed to make the sum of the remaining elements non-negative.

  • Prefix Sums: Prefix Sums is an array which gives the sum of input array till the ith index.
  • Check for Negative Sums: If the total sum of the array (which is the last element of the prefix sum array P) is negative, Output -1. Because in such cases, It will be impossible to make all elements non-negative, If the total sum is already negative.
  • Longest Increasing Subsequence (LIS): Two empty arrays let say Res and LIS[] of size N. Iterates over the prefix sum array Pre[] and for each element let say X, We need to check if X is negative. If it is negative, We need to set LIS[i] to 0 and continues to the next iteration. Otherwise, in approach we uses the upper_bound() function to find the first element in Res that is greater than X and replaces it with X. If no such element is found, We need to append X to the end of Res. The LIS array stores the length of the longest increasing subsequence ending at each index.
  • Output: Finally, we need to output N - LIS[N-1] as required answer, Which is the minimum number of operations required to make all elements of the array non-negative.

Steps taken to solve the problem:

  • Calculate Prefix Sums: Create a new vector P[] of size N for the prefix sums of the array A. Which gives the sum of A[] till index i.
  • Check for Negative Sum: If the total sum of the array (which is the last element of the prefix sum array P[]) is negative, it’s impossible to make all elements non-negative. In this case, output -1.
  • Initialize LIS Arrays: If the total sum is not negative, initialize two new arrays: Res[] and LIS[]. The res array will store the longest increasing subsequence (LIS) of the prefix sum array P, and the LIS array will store the length of the LIS ending at each index.
  • Calculate LIS: Iterate over the prefix sum array P. For each element X, if X is negative, set the corresponding element in LIS to 0 and continue to the next iteration. Otherwise, find the first element in res that is greater than X and replace it with X. If no such element is found, append X to the end of Res.
  • Result: Finally, output the minimum number of operations required to make all elements of the array non-negative. This is given by N - LIS[N-1].

Code to implement the approach:

C++
#include <algorithm>
#include <iostream>
#include <vector>
using namespace std;

// Function to calculate minimum operations
int minOperations(vector<int> A)
{
    int N = A.size();

    // Calculate prefix sums
    vector<long long> P(N);
    P[0] = A[0];
    for (int i = 1; i < N; i++) {
        P[i] = A[i] + P[i - 1];
    }

    // If total sum is negative, return -1
    if (P[N - 1] < 0) {
        return -1;
    }

    // Initialize result and LIS arrays
    vector<long long> res;
    vector<int> lis(N);

    // Calculate LIS of prefix sum array
    for (int i = 0; i < N; i++) {
        long long x = P[i];
        if (x < 0) {
            lis[i] = 0;
            continue;
        }
        auto it = upper_bound(res.begin(), res.end(), x);
        if (it == res.end()) {
            res.push_back(x);
            lis[i] = res.size();
        }
        else {
            *it = x;
            lis[i] = it - res.begin() + 1;
        }
    }

    // Return minimum operations
    return N - lis[N - 1];
}

int main()
{
    vector<int> A = { -2, 1, 1, 1, 1, -2 };
    cout << minOperations(A) << endl;
    return 0;
}
Java
import java.util.ArrayList;
import java.util.List;

class Main {
    public static int minOperations(int[] A) {
        int N = A.length;

        // Calculate prefix sums
        List<Integer> P = new ArrayList<>();
        P.add(A[0]);
        for (int i = 1; i < N; i++) {
            P.add(A[i] + P.get(i - 1));
        }

        // If total sum is negative, return -1
        if (P.get(N - 1) < 0) {
            return -1;
        }

        // Initialize result and LIS arrays
        List<Integer> res = new ArrayList<>();
        int[] lis = new int[N];

        // Calculate LIS of prefix sum array
        for (int i = 0; i < N; i++) {
            int x = P.get(i);
            if (x < 0) {
                lis[i] = 0;
                continue;
            }
            int index = binarySearch(res, x);
            if (index < 0) {
                res.add(-index - 1, x);
                lis[i] = res.size();
            } else {
                res.set(index, x);
                lis[i] = index + 1;
            }
        }

        // Return minimum operations
        return N - lis[N - 1] - 1; // Corrected to account for the first negative value
    }

    // Binary search helper function
    public static int binarySearch(List<Integer> arr, int target) {
        int low = 0;
        int high = arr.size() - 1;
        while (low <= high) {
            int mid = low + (high - low) / 2;
            if (arr.get(mid) == target) {
                return mid;
            } else if (arr.get(mid) < target) {
                low = mid + 1;
            } else {
                high = mid - 1;
            }
        }
        return -(low + 1);
    }

    // Test case
    public static void main(String[] args) {
        int[] A = {-2, 1, 1, 1, 1, -2};
        System.out.println(minOperations(A)); // Output: 4
    }
}
Python3
# Function to calculate minimum operations
def min_operations(A):
    N = len(A)

    # Calculate prefix sums
    P = [0] * N
    P[0] = A[0]
    for i in range(1, N):
        P[i] = A[i] + P[i - 1]

    # If total sum is negative, return -1
    if P[N - 1] < 0:
        return -1

    # Initialize result and LIS arrays
    res = []
    lis = [0] * N

    # Calculate LIS of prefix sum array
    for i in range(N):
        x = P[i]
        if x < 0:
            lis[i] = 0
            continue
        j = 0
        while j < len(res):
            if res[j] > x:
                break
            j += 1
        if j == len(res):
            res.append(x)
            lis[i] = len(res)
        else:
            res[j] = x
            lis[i] = j + 1

    # Return minimum operations
    return N - lis[N - 1]


# Test case
A = [-2, 1, 1, 1, 1, -2]
print(min_operations(A))

# This code is contributed by rohit singh
C#
using System;
using System.Collections.Generic;

class Program
{
    // Function to calculate minimum operations
    static int MinOperations(List<int> A)
    {
        int N = A.Count;

        // Calculate prefix sums
        List<long> P = new List<long>(N);
        P.Add(A[0]);
        for (int i = 1; i < N; i++)
        {
            P.Add(A[i] + P[i - 1]);
        }

        // If total sum is negative, return -1
        if (P[N - 1] < 0)
        {
            return -1;
        }

        // Initialize result and LIS arrays
        List<long> res = new List<long>();
        int[] lis = new int[N];

        // Calculate LIS of prefix sum array
        for (int i = 0; i < N; i++)
        {
            long x = P[i];
            if (x < 0)
            {
                lis[i] = 0;
                continue;
            }
            int index = res.BinarySearch(x);
            if (index < 0)
            {
                index = ~index;
                res.Insert(index, x);
                lis[i] = res.Count;
            }
            else
            {
                res[index] = x;
                lis[i] = index + 1;
            }
        }

        // Return minimum operations
        return N - lis[N - 1] - 1; // Corrected to account for the first negative value
    }

    static void Main(string[] args)
    {
        List<int> A = new List<int> { -2, 1, 1, 1, 1, -2 };
        Console.WriteLine(MinOperations(A));
    }
}
JavaScript
function minOperations(A) {
    const N = A.length;

    // Calculate prefix sums
    const P = [A[0]];
    for (let i = 1; i < N; i++) {
        P.push(A[i] + P[i - 1]);
    }

    // If total sum is negative, return -1
    if (P[N - 1] < 0) {
        return -1;
    }

    // Initialize result and LIS arrays
    const res = [];
    const lis = new Array(N).fill(0);

    // Calculate LIS of prefix sum array
    for (let i = 0; i < N; i++) {
        const x = P[i];
        if (x < 0) {
            lis[i] = 0;
            continue;
        }
        const index = binarySearch(res, x);
        if (index < 0) {
            res.splice(-index - 1, 0, x);
            lis[i] = res.length;
        } else {
            res[index] = x;
            lis[i] = index + 1;
        }
    }

    // Return minimum operations
    return N - lis[N - 1] - 1; // Corrected to account for the first negative value
}

// Binary search helper function
function binarySearch(arr, target) {
    let low = 0;
    let high = arr.length - 1;
    while (low <= high) {
        const mid = Math.floor((low + high) / 2);
        if (arr[mid] === target) {
            return mid;
        } else if (arr[mid] < target) {
            low = mid + 1;
        } else {
            high = mid - 1;
        }
    }
    return -(low + 1);
}

// Test case
const A = [-2, 1, 1, 1, 1, -2];
console.log(minOperations(A));

Output
4

Time Complexity: N*Log(N), As upper_bound() function is used.
Auxiliary Space: O(N), As vectors such as Lis[] and Res[] are used.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads