Minimum removals required to convert given array to a Mountain Array

• Difficulty Level : Expert
• Last Updated : 31 May, 2021

Given an array arr[] consisting of N integers​​​, the task is to find the minimum number of array elements required to be removed to make the given array a mountain array.

A mountain array has the following properties:

• Length of the array ≥ 3.
• There exists some index i (0-based indexing) with 0 < i < N – 1 such that:
• arr < arr < … < arr[i – 1] < arr[i]
• arr[i] > arr[i + 1] > … > arr[arr.length – 1].

Examples:

Input: arr[] = {1, 3, 1}
Output: 0
Explanation: The array itself is a mountain array. Therefore, no removal is required.

Input: arr[] = {2, 1, 1, 5, 6, 2, 3, 1}
Output: 3
Explanation: Removing arr, arr and arr modifies arr[] to {1, 5, 6, 3, 1}, which is a mountain array.

Approach: The idea is to solve this problem using the Bottom-Up Dynamic Programming approach. Follow the steps below to solve the problem:

1. If the length of the given array is less than 3, then the array cannot be converted to a mountain array.
2. Otherwise, traverse the array and for every ith element (0 < i < N), find the length of increasing subsequence in the subarrays {arr, …, arr[i – 1]} and store it in an array, say leftIncreasing[].
3. Similarly, find the length of the increasing subsequence in the subarray {arr[i+1], …., arr[N-1]} for every ith element (0 < i < N), and store it in an array, say rightIncreasing[].
4. Find the index i (0 < i < N) which satisfies the following conditions:
1. The first compulsory condition is the peak condition, which is leftIncreasing[i] > 0 and rightIncreasing[i] > 0.
2. Among all indices, If leftIncreasing[i] + rightIncreasing[i] is the maximum, that index is the peak of the mountain array, say X.
5. Return the result as N – (X + 1), adding one to bring the array index to length.

Illustration:

Consider the array arr[] = {4, 3, 6, 4, 5}
Therefore, leftIncreasing[] = {0, 0, 1, 1, 2} & rightIncreasing[] = {2, 1, 1, 0, 0}.
There is only one index i = 2 (0-based indexing), for which leftIncreasing > 0 and rightIncreasing > 0.
Therefore, X = leftIncreasing + rightIncreasing = 2.
Therefore, the required answer = N – (X + 1) = 5 – (2 + 3)= 2.
One of the possible solutions could be {4, 6, 5} i.e. removing 3 (arr) and 4(arr).

Below is the implementation of the above approach:

C++

 // C++ program of the above approach#include using namespace std; // Utility function to count array// elements required to be removed// to make array a mountain arrayint minRemovalsUtil(int arr[], int n){    int result = 0;    if (n < 3) {        return -1;    }     // Stores length of increasing    // subsequence from [0, i-1]    int leftIncreasing[n] = {0};     // Stores length of increasing    // subsequence from [i + 1, n - 1]    int rightIncreasing[n] = {0};     // Iterate for each position up to    // N - 1 to find the length of subsequence    for (int i = 1; i < n; i++)    {        for (int j = 0; j < i; j++)        {             // If j is less than i, then            // i-th position has leftIncreasing[j]            // + 1 lesser elements including itself            if (arr[j] < arr[i])            {                 // Check if it is the maximum                // obtained so far                leftIncreasing[i]                    = max(leftIncreasing[i],                          leftIncreasing[j] + 1);            }        }    }     // Search for increasing subsequence from right    for (int i = n - 2; i >= 0; i--)    {        for (int j = n - 1; j > i; j--)        {            if (arr[j] < arr[i])            {                rightIncreasing[i]                    = max(rightIncreasing[i],                               rightIncreasing[j] + 1);            }        }    }     // Find the position following the peak    // condition and have maximum leftIncreasing[i]    // + rightIncreasing[i]    for (int i = 0; i < n; i++)    {        if (leftIncreasing[i] != 0            && rightIncreasing[i] != 0)        {            result = max(result,                         leftIncreasing[i]                         + rightIncreasing[i]);        }    }    return n - (result + 1);} // Function to count elements to be// removed to make array a mountain arrayvoid minRemovals(int arr[], int n){    int ans = minRemovalsUtil(arr, n);     // Print the answer    cout << ans;} // Driver Codeint main(){     // Given array    int arr[] = { 2, 1, 1, 5, 6, 2, 3, 1 };    int n = sizeof(arr) / sizeof(arr);           // Function Call    minRemovals(arr, n);    return 0;} // This code is contributed by Dharanendra L V

Java

 // Java program of the above approach import java.io.*;import java.util.*; class GFG {     // Utility function to count array    // elements required to be removed    // to make array a mountain array    public static int minRemovalsUtil(        int[] arr)    {        int result = 0;        if (arr.length < 3) {            return -1;        }         // Stores length of increasing        // subsequence from [0, i-1]        int[] leftIncreasing            = new int[arr.length];         // Stores length of increasing        // subsequence from [i + 1, n - 1]        int[] rightIncreasing = new int[arr.length];         // Iterate for each position up to        // N - 1 to find the length of subsequence        for (int i = 1; i < arr.length; i++) {             for (int j = 0; j < i; j++) {                 // If j is less than i, then                // i-th position has leftIncreasing[j]                // + 1 lesser elements including itself                if (arr[j] < arr[i]) {                     // Check if it is the maximum                    // obtained so far                    leftIncreasing[i]                        = Math.max(                            leftIncreasing[i],                            leftIncreasing[j] + 1);                }            }        }         // Search for increasing subsequence from right        for (int i = arr.length - 2; i >= 0; i--) {            for (int j = arr.length - 1; j > i; j--) {                if (arr[j] < arr[i]) {                    rightIncreasing[i]                        = Math.max(rightIncreasing[i],                                   rightIncreasing[j] + 1);                }            }        }         // Find the position following the peak        // condition and have maximum leftIncreasing[i]        // + rightIncreasing[i]        for (int i = 0; i < arr.length; i++) {            if (leftIncreasing[i] != 0                && rightIncreasing[i] != 0) {                result = Math.max(                    result, leftIncreasing[i]                                + rightIncreasing[i]);            }        }         return arr.length - (result + 1);    }     // Function to count elements to be    // removed to make array a mountain array    public static void minRemovals(int[] arr)    {        int ans = minRemovalsUtil(arr);         // Print the answer        System.out.println(ans);    }     // Driver Code    public static void main(String[] args)    {        // Given array        int[] arr = { 2, 1, 1, 5, 6, 2, 3, 1 };         // Function Call        minRemovals(arr);    }}

Python3

 # Python3 program of the above approach # Utility function to count array# elements required to be removed# to make array a mountain arraydef minRemovalsUtil(arr):         result = 0         if (len(arr) < 3):        return -1     # Stores length of increasing    # subsequence from [0, i-1]    leftIncreasing =  * len(arr)     # Stores length of increasing    # subsequence from [i + 1, n - 1]    rightIncreasing =  * len(arr)     # Iterate for each position up to    # N - 1 to find the length of subsequence    for i in range(1, len(arr)):        for j in range(i):             # If j is less than i, then            # i-th position has leftIncreasing[j]            # + 1 lesser elements including itself            if (arr[j] < arr[i]):                 # Check if it is the maximum                # obtained so far                leftIncreasing[i] = max(leftIncreasing[i],                                        leftIncreasing[j] + 1);                         # Search for increasing subsequence from right    for i in range(len(arr) - 2 , -1, -1):        j = len(arr) - 1                 while j > i:            if (arr[j] < arr[i]) :                rightIncreasing[i] = max(rightIncreasing[i],                                         rightIncreasing[j] + 1)                                                     j -= 1     # Find the position following the peak    # condition and have maximum leftIncreasing[i]    # + rightIncreasing[i]    for i in range(len(arr)):        if (leftIncreasing[i] != 0 and           rightIncreasing[i] != 0):            result = max(result, leftIncreasing[i] +                                rightIncreasing[i]);         return len(arr) - (result + 1) # Function to count elements to be# removed to make array a mountain arraydef minRemovals(arr):         ans = minRemovalsUtil(arr)     # Print the answer    print(ans) # Driver Codeif __name__ == "__main__" :             # Given array    arr = [ 2, 1, 1, 5, 6, 2, 3, 1 ]     # Function Call    minRemovals(arr)     # This code is contributed by AnkThon

C#

 // C# program of the above approachusing System; class GFG{     // Utility function to count array    // elements required to be removed     // to make array a mountain array    public static int minRemovalsUtil(int[] arr)    {        int result = 0;        if (arr.Length < 3)        {            return -1;        }         // Stores length of increasing        // subsequence from [0, i-1]        int[] leftIncreasing            = new int[arr.Length];         // Stores length of increasing        // subsequence from [i + 1, n - 1]        int[] rightIncreasing = new int[arr.Length];         // Iterate for each position up to        // N - 1 to find the length of subsequence        for (int i = 1; i < arr.Length; i++)        {            for (int j = 0; j < i; j++)            {                 // If j is less than i, then                // i-th position has leftIncreasing[j]                // + 1 lesser elements including itself                if (arr[j] < arr[i])                {                     // Check if it is the maximum                    // obtained so far                    leftIncreasing[i]                        = Math.Max(                            leftIncreasing[i],                            leftIncreasing[j] + 1);                }            }        }         // Search for increasing subsequence from right        for (int i = arr.Length - 2; i >= 0; i--)        {            for (int j = arr.Length - 1; j > i; j--)            {                if (arr[j] < arr[i])                {                    rightIncreasing[i]                        = Math.Max(rightIncreasing[i],                                   rightIncreasing[j] + 1);                }            }        }         // Find the position following the peak        // condition and have maximum leftIncreasing[i]        // + rightIncreasing[i]        for (int i = 0; i < arr.Length; i++)        {            if (leftIncreasing[i] != 0                && rightIncreasing[i] != 0)            {                result = Math.Max(result, leftIncreasing[i]                                + rightIncreasing[i]);            }        }        return arr.Length - (result + 1);    }     // Function to count elements to be    // removed to make array a mountain array    public static void minRemovals(int[] arr)    {        int ans = minRemovalsUtil(arr);         // Print the answer        Console.WriteLine(ans);    }     // Driver Code    public static void Main(String[] args)     {        // Given array        int[] arr = {2, 1, 1, 5, 6, 2, 3, 1};         // Function Call        minRemovals(arr);    }}  // This code is contributed by shikhasingrajput.

Javascript


Output:
3

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

My Personal Notes arrow_drop_up