Minimum Operations to Make Array Non-Increasing

Last Updated : 18 Jul, 2026

Given an array arr, find the minimum operations required to make it non-increasing. You can select any one of the following operations and preform it any number of times(including zero) on an array element. 

  • Increment the array element by 1.
  • Decrement the array element by 1.  

Examples:

Input : arr[] = [3, 1, 2, 1]
Output : 1
Explanation : We can convert the array into [3, 1, 1, 1] by changing 3rd element of array i.e. 2  into its previous integer 1 in one step. Hence, only one step is required.

Input : arr[] = [3, 1, 5, 1]
Output : 4
Explanation : We need to decrease 5 to 1 to make array sorted in non-increasing order. The final non-increasing array is [3, 1, 1, 1].

Input : arr[] = [5, 5, 5, 5]
Output : 0
Explanation: The array is already non-increasing.

Try It Yourself
redirect icon

[Naive Approach] Using Recursion - O((maxElement) ^ n) Time and O(n) Space

We recursively try all possible target values for each element (ranging from 0 to the previous element’s value) and compute the cost of converting the current element to that value. Among all such configurations, we take the minimum cost. Since we explore all combinations, the time complexity is exponential.

Step By Step Implementation:

  • Find the maximum of the array and start recursion from index 0 with prev = maxVal.
  • At each index, try all possible values from 0 to prev so that the array remains non-increasing.
  • Calculate the cost to convert the current element into the chosen value using: abs(arr[idx]−val).
  • Recursively solve the remaining array for the next index using the current chosen value as the new prev.
  • Store the minimum cost obtained among all possible choices for the current index.
  • When all elements are processed (idx == n), return 0, and finally return the minimum operations obtained from recursion.
C++
#include <bits/stdc++.h>
using namespace std;

int solve(int idx, int prev, vector<int> &arr)
{
    // Base Case
    if (idx == arr.size())
        return 0;

    int ans = INT_MAX;

    // Current value can be anything from 0 to prev

    for (int val = 0; val <= prev; val++)
    {
        // Cost to convert arr[idx] -> val
        int cost = abs(arr[idx] - val);

        // Recursive call
        cost += solve(idx + 1, val, arr);

        ans = min(ans, cost);
    }

    return ans;
}

int minOperations(vector<int> &arr)
{
    // Maximum value in array
    int maxVal = *max_element(arr.begin(), arr.end());

    // Start recursion
    return solve(0, maxVal, arr);
}

int main()
{
    vector<int> arr = {3, 1, 2, 1};
    cout << minOperations(arr);

    return 0;
}
Java
import java.util.*;

public class GFG {

    static int solve(int idx, int prev, int[] arr)
    {
        // Base Case
        if (idx == arr.length)
            return 0;

        int ans = Integer.MAX_VALUE;

        // Try all possible values from 0 to prev
        for (int val = 0; val <= prev; val++) {

            // Cost to convert arr[idx] -> val
            int cost = Math.abs(arr[idx] - val);

            // Recursive call
            cost += solve(idx + 1, val, arr);

            ans = Math.min(ans, cost);
        }

        return ans;
    }

    static int minOperations(int[] arr)
    {
        // Find maximum element
        int maxVal = Arrays.stream(arr).max().getAsInt();

        // Start recursion
        return solve(0, maxVal, arr);
    }

    public static void main(String[] args)
    {
        int[] arr = { 3, 1, 2, 1 };
        System.out.println(minOperations(arr));
    }
}
Python
def solve(idx, prev, arr):

    # Base Case
    if idx == len(arr):
        return 0

    ans = float('inf')

    # Try all possible values from 0 to prev
    for val in range(prev + 1):

        # Cost to convert arr[idx] -> val
        cost = abs(arr[idx] - val)

        # Recursive call
        cost += solve(idx + 1, val, arr)

        ans = min(ans, cost)

    return ans


def minOperations(arr):

    # Find maximum element
    maxVal = max(arr)

    # Start recursion
    return solve(0, maxVal, arr)


# Driver Code
if __name__ == "__main__":
    arr = [3, 1, 2, 1]
    print(minOperations(arr))
C#
using System;

class GFG {
    static int Solve(int idx, int prev, int[] arr)
    {
        // Base Case
        if (idx == arr.Length)
            return 0;

        int ans = int.MaxValue;

        // Try all possible values from 0 to prev
        for (int val = 0; val <= prev; val++) {
            // Cost to convert arr[idx] -> val
            int cost = Math.Abs(arr[idx] - val);

            // Recursive call
            cost += Solve(idx + 1, val, arr);

            ans = Math.Min(ans, cost);
        }

        return ans;
    }

    static int minOperations(int[] arr)
    {
        // Find maximum element
        int maxVal = arr[0];

        foreach(int num in arr)
        {
            maxVal = Math.Max(maxVal, num);
        }

        // Start recursion
        return Solve(0, maxVal, arr);
    }

    static void Main()
    {
        int[] arr = { 3, 1, 2, 1 };

        Console.WriteLine(minOperations(arr));
    }
}
JavaScript
function solve(idx, prev, arr)
{
    // Base Case
    if (idx === arr.length)
        return 0;

    let ans = Number.MAX_VALUE;

    // Try all possible values from 0 to prev
    for (let val = 0; val <= prev; val++) {

        // Cost to convert arr[idx] -> val
        let cost = Math.abs(arr[idx] - val);

        // Recursive call
        cost += solve(idx + 1, val, arr);

        ans = Math.min(ans, cost);
    }

    return ans;
}

function minOperations(arr)
{
    // Find maximum element
    let maxVal = Math.max(...arr);

    // Start recursion
    return solve(0, maxVal, arr);
}

// Driver Code
let arr = [ 3, 1, 2, 1 ];

console.log(minOperations(arr));

Output
1

[Better Approach] Using Dynamic Programming - O((maxElement ^ 2) * n) Time and O(maxElement * n) Space

The recursive solution tries every possible value for each element, which creates many overlapping states that get recomputed multiple times. To avoid this, we use Bottom-Up DP, where we iteratively build answers for smaller subproblems and store them in a DP table. For each element, we try all possible current values and combine them with valid previous values to maintain the non-increasing order while minimizing the total cost.

Step By Step Implementation:

  • Find the maximum element maxVal in the array.
  • Create a DP table dp[i][j], where dp[i][j] stores the minimum operations needed to make the first i + 1 elements non-increasing if arr[i] is converted to value j.
  • Initialize the first row of the DP table by converting the first element into every possible value from 0 to maxVal.
  • Traverse the array from left to right starting from index 1.
  • For every current value curr, try all possible previous values prev such that prev >= curr to maintain the non-increasing order.
  • Update the DP state using: dp[i][curr] = min⁡(dp[i][curr], dp[i − 1][prev] + abs(arr[i] − curr))
  • The minimum value in the last row of the DP table gives the minimum operations required to make the entire array non-increasing.
C++
#include <algorithm>
#include <climits>
#include <iostream>
#include <vector>

using namespace std;

// Bottom-Up DP Approach dp[i][j] = Minimum operations required to make
// first i elements non-increasing, where current element becomes j.

int minOperations(vector<int> &arr)
{
    int n = arr.size();

    // Maximum element in array
    int maxVal = *max_element(arr.begin(), arr.end());

    vector<vector<int>> dp(n, vector<int>(maxVal + 1, INT_MAX));

    // Base Case for first element
    // We can convert arr[0] to any value j
    for (int j = 0; j <= maxVal; j++)
    {
        dp[0][j] = abs(arr[0] - j);
    }

    for (int i = 1; i < n; i++)
    {
        for (int curr = 0; curr <= maxVal; curr++)
        {
            // Previous value must be >= current value
            // to maintain non-increasing order
            for (int prev = curr; prev <= maxVal; prev++)
            {
                if (dp[i - 1][prev] != INT_MAX)
                {
                    dp[i][curr] = min(dp[i][curr], dp[i - 1][prev] + abs(arr[i] - curr));
                }
            }
        }
    }

    // Find minimum value in last row
    int ans = INT_MAX;

    for (int j = 0; j <= maxVal; j++)
    {
        ans = min(ans, dp[n - 1][j]);
    }

    return ans;
}

int main()
{
    vector<int> arr = {3, 1, 2, 1};
    cout << minOperations(arr);

    return 0;
}
Java
import java.util.*;

class GFG {

    static int minOperations(int[] arr)
    {
        int n = arr.length;

        // Find maximum element
        int maxVal = Arrays.stream(arr).max().getAsInt();

        int[][] dp = new int[n][maxVal + 1];

        // Initialize with large value
        for (int i = 0; i < n; i++) {
            Arrays.fill(dp[i], Integer.MAX_VALUE);
        }

        // Base Case
        for (int j = 0; j <= maxVal; j++) {
            dp[0][j] = Math.abs(arr[0] - j);
        }

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

            for (int curr = 0; curr <= maxVal; curr++) {

                // Previous value must be >= current value
                for (int prev = curr; prev <= maxVal;
                     prev++) {

                    if (dp[i - 1][prev]
                        != Integer.MAX_VALUE) {

                        dp[i][curr] = Math.min(dp[i][curr], dp[i - 1][prev] + Math.abs(arr[i] - curr));
                    }
                }
            }
        }

        // Find minimum answer
        int ans = Integer.MAX_VALUE;

        for (int j = 0; j <= maxVal; j++) {
            ans = Math.min(ans, dp[n - 1][j]);
        }

        return ans;
    }

    public static void main(String[] args)
    {
        int[] arr = { 3, 1, 2, 1 };
        System.out.println(minOperations(arr));
    }
}
Python
import math

def minOperations(arr):

    n = len(arr)

    # Find maximum element
    maxVal = max(arr)

    dp = [[math.inf] * (maxVal + 1) for _ in range(n)]

    # Base Case
    for j in range(maxVal + 1):
        dp[0][j] = abs(arr[0] - j)

    # Fill DP Table
    for i in range(1, n):

        for curr in range(maxVal + 1):

            # Previous value must be >= current value
            for prev in range(curr, maxVal + 1):

                if dp[i - 1][prev] != math.inf:

                    dp[i][curr] = min(
                        dp[i][curr],
                        dp[i - 1][prev] + abs(arr[i] - curr)
                    )

    # Find minimum answer
    ans = math.inf

    for j in range(maxVal + 1):
        ans = min(ans, dp[n - 1][j])

    return ans


# Driver Code
if __name__ == "__main__":
    arr = [3, 1, 2, 1]

    print(minOperations(arr))
C#
using System;

class GFG {
    static int minOperations(int[] arr)
    {
        int n = arr.Length;

        // Find maximum element
        int maxVal = arr[0];

        foreach(int num in arr)
        {
            maxVal = Math.Max(maxVal, num);
        }

        int[, ] dp = new int[n, maxVal + 1];

        // Initialize DP array
        for (int i = 0; i < n; i++) {
            for (int j = 0; j <= maxVal; j++) {
                dp[i, j] = int.MaxValue;
            }
        }

        // Base Case
        for (int j = 0; j <= maxVal; j++) {
            dp[0, j] = Math.Abs(arr[0] - j);
        }

        // Fill DP Table
        for (int i = 1; i < n; i++) {
            for (int curr = 0; curr <= maxVal; curr++) {
                // Previous value must be >= current value
                for (int prev = curr; prev <= maxVal;
                     prev++) {
                    if (dp[i - 1, prev] != int.MaxValue) {
                        dp[i, curr] = Math.Min(
                            dp[i, curr],
                            dp[i - 1, prev]
                                + Math.Abs(arr[i] - curr));
                    }
                }
            }
        }

        // Find minimum answer
        int ans = int.MaxValue;

        for (int j = 0; j <= maxVal; j++) {
            ans = Math.Min(ans, dp[n - 1, j]);
        }

        return ans;
    }

    static void Main()
    {
        int[] arr = { 3, 1, 2, 1 };
        Console.WriteLine(minOperations(arr));
    }
}
JavaScript
function minOperations(arr)
{
    let n = arr.length;

    // Find maximum element
    let maxVal = Math.max(...arr);

    let dp = Array.from(
        {length : n},
        () => Array(maxVal + 1).fill(Number.MAX_VALUE));

    // Base Case
    for (let j = 0; j <= maxVal; j++) {
        dp[0][j] = Math.abs(arr[0] - j);
    }

    // Fill DP Table
    for (let i = 1; i < n; i++) {

        for (let curr = 0; curr <= maxVal; curr++) {

            // Previous value must be >= current value
            for (let prev = curr; prev <= maxVal; prev++) {

                if (dp[i - 1][prev] !== Number.MAX_VALUE) {

                    dp[i][curr] = Math.min(
                        dp[i][curr],
                        dp[i - 1][prev]
                            + Math.abs(arr[i] - curr));
                }
            }
        }
    }

    // Find minimum answer
    let ans = Number.MAX_VALUE;

    for (let j = 0; j <= maxVal; j++) {
        ans = Math.min(ans, dp[n - 1][j]);
    }

    return ans;
}

// Driver Code
let arr = [ 3, 1, 2, 1 ];

console.log(minOperations(arr));

Output
1

[Expected Approach] Using Max-Heap - O(n log n) Time and O(n) Space

First reverse the array so that making it non-increasing becomes making it non-decreasing. While traversing the reversed array, maintain the chosen values in a max-heap. If the largest chosen value is greater than the current element, it violates the non-decreasing order. We reduce that value to the current element and add the difference to the answer. This greedy adjustment ensures the minimum total cost.

Why does this approach work?

  • After reversing, we need: arr[0] <= arr[1] <= arr[2] <= ... <= arr[n-1].
  • When processing an element x, all previously chosen values should be at most x.
  • If the maximum previous value is greater than x, at least one violation exists.
  • The cheapest way to remove that violation is to reduce the largest offending value directly to x.
  • Any optimal solution must pay at least this reduction cost, so performing it immediately is safe.
  • The max-heap helps identify this largest violating value in O(log n) time.

Step By Step Implementation:

  • Reverse the array.
  • Initialize a max-heap and a variable cost = 0.
  • Traverse the reversed array from left to right.
  • Insert the current element into the max-heap.
  • If the largest value in the heap is greater than the current element: Add the difference to cost, remove the largest value from the heap and insert the current element instead.
  • After processing all elements, return cost.
C++
#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;

int minOperations(vector<int>& arr) {
    reverse(arr.begin(), arr.end());

    priority_queue<int> pq;
    int cost = 0;

    for (int x : arr) {
        pq.push(x);

        // Reduce the largest value if it exceeds x.
        if (pq.top() > x) {
            cost += pq.top() - x;
            pq.pop();
            pq.push(x);
        }
    }

    return cost;
}

int main() {
    vector<int> arr = {3, 1, 2, 1};

    cout << minOperations(arr);

    return 0;
}
Java
import java.util.Collections;
import java.util.PriorityQueue;

class GFG {

    static int minOperations(int[] arr) {
        int n = arr.length;

        for (int i = 0; i < n / 2; i++) {
            int temp = arr[i];
            arr[i] = arr[n - 1 - i];
            arr[n - 1 - i] = temp;
        }

        PriorityQueue<Integer> pq =
            new PriorityQueue<>(Collections.reverseOrder());

        int cost = 0;

        for (int x : arr) {
            pq.offer(x);

            // Reduce the largest value if it exceeds x.
            if (pq.peek() > x) {
                cost += pq.peek() - x;
                pq.poll();
                pq.offer(x);
            }
        }

        return cost;
    }

    public static void main(String[] args) {
        int[] arr = {3, 1, 2, 1};

        System.out.println(minOperations(arr));
    }
}
Python
import heapq

def minOperations(arr):
    arr.reverse()

    heap = []
    cost = 0

    for x in arr:
        heapq.heappush(heap, -x)

        # Reduce the largest value if it exceeds x.
        if -heap[0] > x:
            cost += (-heap[0]) - x
            heapq.heappop(heap)
            heapq.heappush(heap, -x)

    return cost

arr = [3, 1, 2, 1]

print(minOperations(arr))
C#
using System;
using System.Collections.Generic;

class GFG
{
    static int MinOperations(int[] arr)
    {
        Array.Reverse(arr);

        PriorityQueue<int, int> pq = new();

        int cost = 0;

        foreach (int x in arr)
        {
            pq.Enqueue(x, -x);

            // Reduce the largest value if it exceeds x.
            if (pq.Peek() > x)
            {
                cost += pq.Peek() - x;
                pq.Dequeue();
                pq.Enqueue(x, -x);
            }
        }

        return cost;
    }

    static void Main()
    {
        int[] arr = { 3, 1, 2, 1 };

        Console.WriteLine(MinOperations(arr));
    }
}
JavaScript
class MaxHeap {
    constructor() {
        this.heap = [];
    }

    push(x) {
        this.heap.push(x);

        let i = this.heap.length - 1;

        while (i > 0) {
            let p = Math.floor((i - 1) / 2);

            if (this.heap[p] >= this.heap[i]) break;

            [this.heap[p], this.heap[i]] =
                [this.heap[i], this.heap[p]];

            i = p;
        }
    }

    pop() {
        const top = this.heap[0];
        const last = this.heap.pop();

        if (this.heap.length) {
            this.heap[0] = last;

            let i = 0;

            while (true) {
                let l = 2 * i + 1;
                let r = 2 * i + 2;
                let largest = i;

                if (l < this.heap.length &&
                    this.heap[l] > this.heap[largest]) {
                    largest = l;
                }

                if (r < this.heap.length &&
                    this.heap[r] > this.heap[largest]) {
                    largest = r;
                }

                if (largest === i) break;

                [this.heap[i], this.heap[largest]] =
                    [this.heap[largest], this.heap[i]];

                i = largest;
            }
        }

        return top;
    }

    top() {
        return this.heap[0];
    }
}

function minOperations(arr) {
    arr.reverse();

    const pq = new MaxHeap();
    let cost = 0;

    for (const x of arr) {
        pq.push(x);

        // Reduce the largest value if it exceeds x.
        if (pq.top() > x) {
            cost += pq.top() - x;
            pq.pop();
            pq.push(x);
        }
    }

    return cost;
}

// Driver Code
const arr = [3, 1, 2, 1];

console.log(minOperations(arr));

Output
1
Comment