Remove minimum elements from either side such that 2*min becomes more than max
Last Updated :
18 Sep, 2023
Given an unsorted array, trim the array such that twice of minimum is greater than maximum in the trimmed array. Elements should be removed either end of the array.
Number of removals should be minimum.
Examples:
arr[] = {4, 5, 100, 9, 10, 11, 12, 15, 200}
Output: 4
We need to remove 4 elements (4, 5, 100, 200)
so that 2*min becomes more than max.
arr[] = {4, 7, 5, 6}
Output: 0
We don't need to remove any element as
4*2 > 7 (Note that min = 4, max = 8)
arr[] = {20, 7, 5, 6}
Output: 1
We need to remove 20 so that 2*min becomes
more than max
arr[] = {20, 4, 1, 3}
Output: 3
We need to remove any three elements from ends
like 20, 4, 1 or 4, 1, 3 or 20, 3, 1 or 20, 4, 1
Naive Solution:
A naive solution is to try every possible case using recurrence. Following is the naive recursive algorithm. Note that the algorithm only returns minimum numbers of removals to be made, it doesn’t print the trimmed array. It can be easily modified to print the trimmed array as well.
// Returns minimum number of removals to be made in
// arr[l..h]
minRemovals(int arr[], int l, int h)
1) Find min and max in arr[l..h]
2) If 2*min > max, then return 0.
3) Else return minimum of "minRemovals(arr, l+1, h) + 1"
and "minRemovals(arr, l, h-1) + 1"
Following is the implementation of above algorithm.
C++
#include <iostream>
using namespace std;
int min( int a, int b) { return (a < b)? a : b;}
int min( int arr[], int l, int h)
{
int mn = arr[l];
for ( int i=l+1; i<=h; i++)
if (mn > arr[i])
mn = arr[i];
return mn;
}
int max( int arr[], int l, int h)
{
int mx = arr[l];
for ( int i=l+1; i<=h; i++)
if (mx < arr[i])
mx = arr[i];
return mx;
}
int minRemovals( int arr[], int l, int h)
{
if (l >= h) return 0;
int mn = min(arr, l, h);
int mx = max(arr, l, h);
if (2*mn > mx)
return 0;
return min(minRemovals(arr, l+1, h),
minRemovals(arr, l, h-1)) + 1;
}
int main()
{
int arr[] = {4, 5, 100, 9, 10, 11, 12, 15, 200};
int n = sizeof (arr)/ sizeof (arr[0]);
cout << minRemovals(arr, 0, n-1);
return 0;
}
|
Java
import java.io.*;
import java.util.*;
class GFG {
static int min( int a, int b) { return (a < b) ? a : b; }
static int min( int arr[], int l, int h)
{
int mn = arr[l];
for ( int i = l + 1 ; i <= h; i++)
if (mn > arr[i])
mn = arr[i];
return mn;
}
static int max( int arr[], int l, int h)
{
int mx = arr[l];
for ( int i = l + 1 ; i <= h; i++)
if (mx < arr[i])
mx = arr[i];
return mx;
}
static int minRemovals( int arr[], int l, int h)
{
if (l >= h)
return 0 ;
int mn = min(arr, l, h);
int mx = max(arr, l, h);
if ( 2 * mn > mx)
return 0 ;
return min(minRemovals(arr, l + 1 , h),
minRemovals(arr, l, h - 1 ))
+ 1 ;
}
public static void main(String[] args)
{
int arr[] = { 4 , 5 , 100 , 9 , 10 , 11 , 12 , 15 , 200 };
int n = arr.length;
System.out.print(minRemovals(arr, 0 , n - 1 ));
}
}
|
Python3
def mini(arr, l, h):
mn = arr[l]
for i in range (l + 1 , h + 1 ):
if (mn > arr[i]):
mn = arr[i]
return mn
def max (arr, l, h):
mx = arr[l]
for i in range (l + 1 , h + 1 ):
if (mx < arr[i]):
mx = arr[i]
return mx
def minRemovals(arr, l, h):
if (l > = h):
return 0
mn = mini(arr, l, h)
mx = max (arr, l, h)
if ( 2 * mn > mx):
return 0
return ( min (minRemovals(arr, l + 1 , h),
minRemovals(arr, l, h - 1 )) + 1 )
arr = [ 4 , 5 , 100 , 9 , 10 ,
11 , 12 , 15 , 200 ]
n = len (arr)
print (minRemovals(arr, 0 , n - 1 ))
|
C#
using System;
class GFG
{
static int min( int a, int b) { return (a < b)? a : b;}
static int min( int [] arr, int l, int h)
{
int mn = arr[l];
for ( int i=l+1; i<=h; i++)
if (mn > arr[i])
mn = arr[i];
return mn;
}
static int max( int [] arr, int l, int h)
{
int mx = arr[l];
for ( int i=l+1; i<=h; i++)
if (mx < arr[i])
mx = arr[i];
return mx;
}
static int minRemovals( int [] arr, int l, int h)
{
if (l >= h) return 0;
int mn = min(arr, l, h);
int mx = max(arr, l, h);
if (2*mn > mx)
return 0;
return min(minRemovals(arr, l+1, h),
minRemovals(arr, l, h-1)) + 1;
}
public static void Main()
{
int [] arr = {4, 5, 100, 9, 10, 11, 12, 15, 200};
int n = arr.Length;
Console.Write(minRemovals(arr, 0, n-1));
}
}
|
PHP
<?php
function min_1(& $arr , $l , $h )
{
$mn = $arr [ $l ];
for ( $i = $l + 1; $i <= $h ; $i ++)
if ( $mn > $arr [ $i ])
$mn = $arr [ $i ];
return $mn ;
}
function max_1(& $arr , $l , $h )
{
$mx = $arr [ $l ];
for ( $i = $l + 1; $i <= $h ; $i ++)
if ( $mx < $arr [ $i ])
$mx = $arr [ $i ];
return $mx ;
}
function minRemovals(& $arr , $l , $h )
{
if ( $l >= $h ) return 0;
$mn = min_1( $arr , $l , $h );
$mx = max_1( $arr , $l , $h );
if (2 * $mn > $mx )
return 0;
return min(minRemovals( $arr , $l + 1, $h ),
minRemovals( $arr , $l , $h - 1)) + 1;
}
$arr = array (4, 5, 100, 9, 10,
11, 12, 15, 200);
$n = sizeof( $arr );
echo minRemovals( $arr , 0, $n - 1);
?>
|
Javascript
<script>
function min(arr,l,h)
{
let mn = arr[l];
for (let i=l+1; i<=h; i++)
{
if (mn > arr[i])
mn = arr[i];
}
return mn;
}
function max(arr,l,h)
{
let mx = arr[l];
for (let i=l+1; i<=h; i++)
{
if (mx < arr[i])
mx = arr[i];
}
return mx;
}
function minRemovals(arr,l,h)
{
if (l >= h)
return 0;
let mn = min(arr, l, h);
let mx = max(arr, l, h);
if (2*mn > mx)
return 0;
return Math.min(minRemovals(arr, l+1, h),minRemovals(arr, l, h-1)) + 1;
}
let arr = [4, 5, 100, 9, 10, 11, 12, 15, 200];
let n = arr.length;
document.write(minRemovals(arr, 0, n - 1));
</script>
|
Time complexity: Time complexity of the above function can be written as following
T(n) = 2T(n-1) + O(n)
An upper bound on solution of above recurrence would be O(n x 2n).
Auxiliary Space: O(1)
Dynamic Programming:
The above recursive code exhibits many overlapping subproblems. For example minRemovals(arr, l+1, h-1) is evaluated twice. So Dynamic Programming is the choice to optimize the solution. Following is Dynamic Programming based solution.
C++
#include <iostream>
using namespace std;
int min( int a, int b) { return (a < b)? a : b;}
int min( int arr[], int l, int h)
{
int mn = arr[l];
for ( int i=l+1; i<=h; i++)
if (mn > arr[i])
mn = arr[i];
return mn;
}
int max( int arr[], int l, int h)
{
int mx = arr[l];
for ( int i=l+1; i<=h; i++)
if (mx < arr[i])
mx = arr[i];
return mx;
}
int minRemovalsDP( int arr[], int n)
{
int table[n][n], gap, i, j, mn, mx;
for (gap = 0; gap < n; ++gap)
{
for (i = 0, j = gap; j < n; ++i, ++j)
{
mn = min(arr, i, j);
mx = max(arr, i, j);
table[i][j] = (2*mn > mx)? 0: min(table[i][j-1]+1,
table[i+1][j]+1);
}
}
return table[0][n-1];
}
int main()
{
int arr[] = {20, 4, 1, 3};
int n = sizeof (arr)/ sizeof (arr[0]);
cout << minRemovalsDP(arr, n);
return 0;
}
|
Java
import java.util.*;
import java.io.*;
class GFG {
static int min( int a, int b) {
return (a < b) ? a : b;
}
static int min( int arr[], int l, int h) {
int mn = arr[l];
for ( int i = l + 1 ; i <= h; i++) {
if (mn > arr[i]) {
mn = arr[i];
}
}
return mn;
}
static int max( int arr[], int l, int h) {
int mx = arr[l];
for ( int i = l + 1 ; i <= h; i++) {
if (mx < arr[i]) {
mx = arr[i];
}
}
return mx;
}
static int minRemovalsDP( int arr[], int n) {
int table[][] = new int [n][n], gap, i, j, mn, mx;
for (gap = 0 ; gap < n; ++gap) {
for (i = 0 , j = gap; j < n; ++i, ++j) {
mn = min(arr, i, j);
mx = max(arr, i, j);
table[i][j] = ( 2 * mn > mx) ? 0 : min(table[i][j - 1 ] + 1 ,
table[i + 1 ][j] + 1 );
}
}
return table[ 0 ][n - 1 ];
}
public static void main(String[] args) {
int arr[] = { 20 , 4 , 1 , 3 };
int n = arr.length;
System.out.println(minRemovalsDP(arr, n));
}
}
|
Python3
def min1(arr, l, h):
mn = arr[l];
for i in range (l + 1 ,h + 1 ):
if (mn > arr[i]):
mn = arr[i];
return mn;
def max1(arr, l, h):
mx = arr[l];
for i in range (l + 1 , h + 1 ):
if (mx < arr[i]):
mx = arr[i];
return mx;
def minRemovalsDP(arr, n):
table = [[ 0 for x in range (n)] for y in range (n)];
for gap in range (n):
i = 0 ;
for j in range (gap,n):
mn = min1(arr, i, j);
mx = max1(arr, i, j);
table[i][j] = 0 if ( 2 * mn > mx) else min (table[i][j - 1 ] + 1 ,table[i + 1 ][j] + 1 );
i + = 1 ;
return table[ 0 ][n - 1 ];
arr = [ 20 , 4 , 1 , 3 ];
n = len (arr);
print (minRemovalsDP(arr, n));
|
C#
using System;
public class GFG {
static int min( int a, int b) {
return (a < b) ? a : b;
}
static int min( int []arr, int l, int h) {
int mn = arr[l];
for ( int i = l + 1; i <= h; i++) {
if (mn > arr[i]) {
mn = arr[i];
}
}
return mn;
}
static int max( int []arr, int l, int h) {
int mx = arr[l];
for ( int i = l + 1; i <= h; i++) {
if (mx < arr[i]) {
mx = arr[i];
}
}
return mx;
}
static int minRemovalsDP( int []arr, int n) {
int [,]table = new int [n,n];
int gap, i, j, mn, mx;
for (gap = 0; gap < n; ++gap) {
for (i = 0, j = gap; j < n; ++i, ++j) {
mn = min(arr, i, j);
mx = max(arr, i, j);
table[i,j] = (2 * mn > mx) ? 0 : min(table[i,j - 1] + 1,
table[i + 1,j] + 1);
}
}
return table[0,n - 1];
}
public static void Main() {
int []arr = {20, 4, 1, 3};
int n = arr.Length;
Console.WriteLine(minRemovalsDP(arr, n));
}
}
|
PHP
<?php
function min1( $arr , $l , $h )
{
$mn = $arr [ $l ];
for ( $i = $l + 1; $i <= $h ; $i ++)
if ( $mn > $arr [ $i ])
$mn = $arr [ $i ];
return $mn ;
}
function max1( $arr , $l , $h )
{
$mx = $arr [ $l ];
for ( $i = $l + 1; $i <= $h ; $i ++)
if ( $mx < $arr [ $i ])
$mx = $arr [ $i ];
return $mx ;
}
function minRemovalsDP( $arr , $n )
{
$table = array_fill (0, $n ,
array_fill (0, $n , 0));
for ( $gap = 0; $gap < $n ; ++ $gap )
{
for ( $i = 0, $j = $gap ; $j < $n ; ++ $i , ++ $j )
{
$mn = min1( $arr , $i , $j );
$mx = max1( $arr , $i , $j );
$table [ $i ][ $j ] = (2 * $mn > $mx ) ? 0 :
min( $table [ $i ][ $j - 1] + 1,
$table [ $i + 1][ $j ] + 1);
}
}
return $table [0][ $n - 1];
}
$arr = array (20, 4, 1, 3);
$n = count ( $arr );
echo minRemovalsDP( $arr , $n );
?>
|
Javascript
<script>
function minq(a, b)
{
return (a < b) ? a : b;
}
function min(arr, l, h)
{
var mn = arr[l];
for (i = l + 1; i <= h; i++)
{
if (mn > arr[i])
{
mn = arr[i];
}
}
return parseInt(mn);
}
function max(arr, l, h)
{
var mx = arr[l];
for (i = l + 1; i <= h; i++)
{
if (mx < arr[i])
{
mx = arr[i];
}
}
return parseInt(mx);
}
function minRemovalsDP(arr, n)
{
var table = Array(n);
var gap, i, j, mn, mx;
for (i = 0; i < n; i++)
table[i] = Array(n).fill(0);
for (gap = 0; gap < n; ++gap)
{
for (i = 0, j = gap; j < n; ++i, ++j)
{
mn = min(arr, i, j);
mx = max(arr, i, j);
table[i][j] = parseInt((2 * mn > mx) ?
0 : minq(table[i][j - 1] + 1,
table[i + 1][j] + 1));
}
}
return table[0][n - 1];
}
var arr = [ 20, 4, 1, 3 ];
var n = arr.length;
document.write(minRemovalsDP(arr, n));
</script>
|
Time Complexity: O(n3) where n is the number of elements in arr[].
Auxiliary Space: O(n^2)
Further Optimizations:
The above code can be optimized in many ways.
- We can avoid calculation of min() and/or max() when min and/or max is/are not changed by removing corner elements.
- We can pre-process the array and build segment tree in O(n) time. After the segment tree is built, we can query range minimum and maximum in O(Logn) time. The overall time complexity is reduced to O(n2Logn) time.
A O(n^2) Solution:
The idea is to find the maximum sized subarray such that 2*min > max. We run two nested loops, the outer loop chooses a starting point and the inner loop chooses ending point for the current starting point. We keep track of longest subarray with the given property.
Following is the implementation of the above approach. Thanks to Richard Zhang for suggesting this solution.
C++
#include <iostream>
#include <climits>
using namespace std;
int minRemovalsDP( int arr[], int n)
{
int longest_start = -1, longest_end = 0;
for ( int start=0; start<n; start++)
{
int min = INT_MAX, max = INT_MIN;
for ( int end = start; end < n; end ++)
{
int val = arr[end];
if (val < min) min = val;
if (val > max) max = val;
if (2 * min <= max) break ;
if (end - start > longest_end - longest_start ||
longest_start == -1)
{
longest_start = start;
longest_end = end;
}
}
}
if (longest_start == -1) return n;
return (n - (longest_end - longest_start + 1));
}
int main()
{
int arr[] = {4, 5, 100, 9, 10, 11, 12, 15, 200};
int n = sizeof (arr)/ sizeof (arr[0]);
cout << minRemovalsDP(arr, n);
return 0;
}
|
Java
import java.util.*;
import java.io.*;
class GFG {
static int minRemovalsDP( int arr[], int n) {
int longest_start = - 1 , longest_end = 0 ;
for ( int start = 0 ; start < n; start++) {
int min = Integer.MAX_VALUE, max = Integer.MIN_VALUE;
for ( int end = start; end < n; end++) {
int val = arr[end];
if (val < min) {
min = val;
}
if (val > max) {
max = val;
}
if ( 2 * min <= max) {
break ;
}
if (end - start > longest_end - longest_start
|| longest_start == - 1 ) {
longest_start = start;
longest_end = end;
}
}
}
if (longest_start == - 1 ) {
return n;
}
return (n - (longest_end - longest_start + 1 ));
}
public static void main(String[] args) {
int arr[] = { 4 , 5 , 100 , 9 , 10 , 11 , 12 , 15 , 200 };
int n = arr.length;
System.out.println(minRemovalsDP(arr, n));
}
}
|
Python3
import sys;
def minRemovalsDP(arr, n):
longest_start = - 1 ;
longest_end = 0 ;
for start in range (n):
min = sys.maxsize;
max = - sys.maxsize;
for end in range (start,n):
val = arr[end];
if (val < min ):
min = val;
if (val > max ):
max = val;
if ( 2 * min < = max ):
break ;
if (end - start > longest_end - longest_start or longest_start = = - 1 ):
longest_start = start;
longest_end = end;
if (longest_start = = - 1 ):
return n;
return (n - (longest_end - longest_start + 1 ));
arr = [ 4 , 5 , 100 , 9 , 10 , 11 , 12 , 15 , 200 ];
n = len (arr);
print (minRemovalsDP(arr, n));
|
C#
using System;
public class GFG {
static int minRemovalsDP( int []arr, int n) {
int longest_start = -1, longest_end = 0;
for ( int start = 0; start < n; start++) {
int min = int .MaxValue, max = int .MinValue;
for ( int end = start; end < n; end++) {
int val = arr[end];
if (val < min) {
min = val;
}
if (val > max) {
max = val;
}
if (2 * min <= max) {
break ;
}
if (end - start > longest_end - longest_start
|| longest_start == -1) {
longest_start = start;
longest_end = end;
}
}
}
if (longest_start == -1) {
return n;
}
return (n - (longest_end - longest_start + 1));
}
public static void Main() {
int []arr = {4, 5, 100, 9, 10, 11, 12, 15, 200};
int n = arr.Length;
Console.WriteLine(minRemovalsDP(arr, n));
}
}
|
PHP
<?php
function minRemovalsDP( $arr , $n )
{
$longest_start = -1;
$longest_end = 0;
for ( $start = 0; $start < $n ; $start ++)
{
$min = PHP_INT_MAX;
$max = PHP_INT_MIN;
for ( $end = $start ; $end < $n ; $end ++)
{
$val = $arr [ $end ];
if ( $val < $min ) $min = $val ;
if ( $val > $max ) $max = $val ;
if (2 * $min <= $max ) break ;
if ( $end - $start > $longest_end - $longest_start ||
$longest_start == -1)
{
$longest_start = $start ;
$longest_end = $end ;
}
}
}
if ( $longest_start == -1) return $n ;
return ( $n - ( $longest_end - $longest_start + 1));
}
$arr = array (4, 5, 100, 9, 10, 11, 12, 15, 200);
$n = sizeof( $arr );
echo minRemovalsDP( $arr , $n );
?>
|
Javascript
<script>
function minRemovalsDP(arr,n)
{
let longest_start = -1, longest_end = 0;
for (let start = 0; start < n; start++)
{
let min = Number.MAX_VALUE, max = Number.MIN_VALUE;
for (let end = start; end < n; end++)
{
let val = arr[end];
if (val < min)
{
min = val;
}
if (val > max)
{
max = val;
}
if (2 * min <= max)
{
break ;
}
if (end - start > longest_end - longest_start
|| longest_start == -1)
{
longest_start = start;
longest_end = end;
}
}
}
if (longest_start == -1)
{
return n;
}
return (n - (longest_end - longest_start + 1));
}
let arr=[4, 5, 100, 9, 10, 11, 12, 15, 200];
let n = arr.length;
document.write(minRemovalsDP(arr, n));
</script>
|
Time Complexity: O(N2)
Auxiliary Space: O(1)
Like Article
Suggest improvement
Share your thoughts in the comments
Please Login to comment...