Open In App

Minimum operations to reduce array elements to zero using prefix operations and updates

Last Updated : 26 Mar, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

Given an array arr[] of length N. We can apply 2 types of operations on element of arr[]:

  • Choose a prefix let say arr[0, i] (0 <= i < N) and decrement all elements of prefix by 1. This operation can only apply if all elements in the prefix > 0.
  • Choose an element arr[i] (0 <= i < N) and update it to 0.

The task is to output the minimum number of operations required to reduce all the elements to 0.

Examples:

Input: N = 5, arr[] = {1, 1, 2, 2, 2}
Output: 4
Explanation: The operations are performed as below:

  • Apply 1st type of operation on prefix arr[0, 4]. Then updated arr[] = {0, 0, 1, 1, 1}.
  • Make arr[2], arr[3], and arr[4] to 0 by using 2nd type of operation one by one. This will require 3 operations.

In total 4 operations are required to make all elements 0. Therefore, output is 4.

Input: N = 9, arr[] = {5, 3, 3, 5, 2, 4, 5, 2, 1}
Output: 7
Explanation: It can be verified that the minimum number of operations will be 7. If they are used optimally.

Approach: Implement the idea below to solve the problem

This problem is observation based. Let us try to understand those observations:

  • Observation 1: By using second operation we can make all elements 0 by using exactly N number of operations. In each operation we can set arr[i] for (1 <= i <= N) to 0. Thus, it must be noted that the minimum number of operations are bounded in the range [1, N].
  • Observation 2: It will be helpful to apply 1st type of operation because it decrements all the elements of prefix by 1 in a single operation. But this operation can be applied only at elements arr[i] of prefix arr[0, i], where all elements are greater than 0. From here we get the intuition that, we should apply 1st type of operation on the prefix minimums. As prefix minimum is the minimum element of a prefix present at last index. So, using operation on such element won’t make any element into 0 (which are left to the prefix min element). Therefore, create an array of prefix minimums and try to find the minimum number of operations for each prefix minimum in increasing order. For example, the prefix minimum let say M[] of arr[] = {3, 3, 4, 5, 2, 2, 2} will be M[] = {3, 3, 2, 2, 2}. It can be obtained by traversing arr[] and each iteration store element arr[i], if (arr[i] <= CurrentElement) and then set CurrentElement = arr[i]. Initially, CurrentElement is set to arr[0]. Now, we can see that obtained M[] is in decreasing order. So, we will find minimum number of operations from smaller Prefix minimums first. That’s why we will process M[] from right side.

How to calculate minimum moves for each prefix minimum present in M[]:

  • With X prefix moves, the maximum number of elements we can set to 0 is exactly the elements of M that are <= X. Let us take it in a variable Zx.
  • Computing Zx: If X is processed in ascending order, Zx will correspond to some increasing suffix of M. Once Zx is known for a fixed X, we know that the total number of moves needed (including making X prefix moves) will be (X + (N – Zx)).

Therefore, final answer is the minimum of (X + N – Zx) across all (0 <= X < N).

Step-by-step algorithm:

  • Declare the variable let say Mini to store the Prefix Minimum till now and initialize it with arr[0] initially.
  • Declare an ArrayList let say M[] to store all the Prefix Minimums of arr[].
  • Add Mini (First Prefix Minimum) into M[].
  • Run a loop from i = 1 to i < N and follow below mentioned steps under the scope of loop:
    • If (arr[i] <= Mini)
      • Mini = arr[i]
      • Add Mini into M[]
  • Declare 3 variables let say X, Zx and Minn. Initialize Minn = N.
  • Run a loop from i = (M.size() – 1) to i >= 0 and follow below mentioned steps under the scope of loop:
    • If (X == M.get(i))
      • Increment Zx.
    • Else
      • X = M.get(i)
      • Increment Zx.
    • Minn = min (X + (N – Zx), Minn)
  • Output Minn.

Below is the implementation of the algorithm:

C++
#include <iostream>
#include <vector>

using namespace std;

// Function to find the minimum operations
void Min_Ops(int N, int arr[]) {
    // Variable to store the minimum element
    // so far while traversing
    int mini = arr[0];

    // Vector to store the prefix minimums
    vector<int> M;
    // Adding first prefix minimum which is arr[0]
    M.push_back(mini);

    // Finding and storing prefix minimum in Vector
    for (int i = 1; i < N; i++) {
        if (arr[i] <= mini) {
            mini = arr[i];
            M.push_back(mini);
        }
    }

    // finding the number of operations for each prefix
    // minimum element
    int x = 0, zx = 0, minn = N;
    for (int i = M.size() - 1; i >= 0; i--) {
        if (x == M[i]) {
            zx++;
        } else {
            x = M[i];
            zx++;
        }
        minn = min(x + (N - zx), minn);
    }
    cout << minn << endl;
}

// Driver Function
int main() {
    // Inputs
    int N = 9;
    int arr[] = {5, 3, 3, 5, 2, 4, 5, 2, 1};

    // Function call
    Min_Ops(N, arr);

    return 0;
}

// This code is contributed by akshitaguprzj3
Java
import java.util.ArrayList;

public class Main {
    // Driver Function
    public static void main(String[] args) {
        // Inputs
        int N = 9;
        int[] arr = { 5, 3, 3, 5, 2, 4, 5, 2, 1 };

        // Function call
        minOps(N, arr);
    }

    public static void minOps(int N, int[] arr) {
        // Variable to store the minimum element
        // so far while traversing
        int mini = arr[0];

        // ArrayList to store the prefix minimums
        ArrayList<Integer> M = new ArrayList<>();
        // Adding first prefix minimum which is arr[0]
        M.add(mini);

        // Finding and storing prefix minimum in ArrayList
        for (int i = 1; i < N; i++) {
            if (arr[i] <= mini) {
                mini = arr[i];
                M.add(mini);
            }
        }

        // Finding the number of operations for each prefix
        // minimum element
        int x = 0, zx = 0, minn = N;
        for (int i = M.size() - 1; i >= 0; i--) {
            if (x == M.get(i)) {
                zx++;
            } else {
                x = M.get(i);
                zx++;
            }
            minn = Math.min(x + (N - zx), minn);
        }
        System.out.println(minn);
    }
}
C#
using System;
using System.Collections.Generic;

class Program {
    // Function to find the minimum operations
    static void Min_Ops(int N, int[] arr)
    {
        // Variable to store the minimum element
        // so far while traversing
        int mini = arr[0];

        // List to store the prefix minimums
        List<int> M = new List<int>();
        // Adding first prefix minimum which is arr[0]
        M.Add(mini);

        // Finding and storing prefix minimum in List
        for (int i = 1; i < N; i++) {
            if (arr[i] <= mini) {
                mini = arr[i];
                M.Add(mini);
            }
        }

        // finding the number of operations for each prefix
        // minimum element
        int x = 0, zx = 0, minn = N;
        for (int i = M.Count - 1; i >= 0; i--) {
            if (x == M[i]) {
                zx++;
            }
            else {
                x = M[i];
                zx++;
            }
            minn = Math.Min(x + (N - zx), minn);
        }
        Console.WriteLine(minn);
    }

    // Driver Function
    static void Main(string[] args)
    {
        // Inputs
        int N = 9;
        int[] arr = { 5, 3, 3, 5, 2, 4, 5, 2, 1 };

        // Function call
        Min_Ops(N, arr);
    }
}
JavaScript
// Function to calculate minimum operations
function minOps(N, arr) {
    // Variable to store the minimum element so far while traversing
    let mini = arr[0];

    // Array to store the prefix minimums
    let M = [];
    // Adding first prefix minimum which is arr[0]
    M.push(mini);

    // Finding and storing prefix minimums in the array
    for (let i = 1; i < N; i++) {
        if (arr[i] <= mini) {
            mini = arr[i];
            M.push(mini);
        }
    }

    // Finding the number of operations for each prefix minimum element
    let x = 0, zx = 0, minn = N;
    for (let i = M.length - 1; i >= 0; i--) {
        if (x === M[i]) {
            zx++;
        } else {
            x = M[i];
            zx++;
        }
        minn = Math.min(x + (N - zx), minn);
    }
    console.log(minn);
}

// Main function
function main() {
    // Inputs
    let N = 9;
    let arr = [5, 3, 3, 5, 2, 4, 5, 2, 1];

    // Function call
    minOps(N, arr);
}

// Call the main function
main();
Python3
# Function to find the minimum operations
def min_ops(N, arr):
    # Variable to store the minimum element
    # so far while traversing
    mini = arr[0]

    # List to store the prefix minimums
    M = [mini]

    # Finding and storing prefix minimum in List
    for i in range(1, N):
        if arr[i] <= mini:
            mini = arr[i]
            M.append(mini)

    # Finding the number of operations for each prefix minimum element
    x, zx, minn = 0, 0, N
    for i in range(len(M) - 1, -1, -1):
        if x == M[i]:
            zx += 1
        else:
            x = M[i]
            zx += 1
        minn = min(x + (N - zx), minn)

    print(minn)

# Driver Function
if __name__ == "__main__":
    # Inputs
    N = 9
    arr = [5, 3, 3, 5, 2, 4, 5, 2, 1]

    # Function call
    min_ops(N, arr)

Output
7




Time Complexity: O(N), where N is the size of input array arr[].
Auxiliary Space: O(N), As ArrayList PreMins is used to store the Prefix Minimums.



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads