Minimum number of operations required to make all the elements positive
Last Updated :
04 Apr, 2024
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],
w
here 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 Re
s
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));
Time Complexity: N*Log(N), As upper_bound() function is used.
Auxiliary Space: O(N), As vectors such as Lis[] and Res[] are used.
Share your thoughts in the comments
Please Login to comment...