Given an unsorted array, trim the array such that twice of minimum is greater than the maximum in the trimmed array. Elements should be removed from either end of the array. The number of removals should be minimum.
Examples:
Input: 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. Input: arr[] = {4, 7, 5, 6} Output: 0 We don’t need to remove any element as 4*2 > 7 Input: arr[] = {20, 7, 5, 6} Output: 1
Approach:
We have discussed various approaches to solve this problem in O(n
3
), O(n
2
* logn), and O(n
2
) time in
. In this articles, we are going to discuss a O(n * logn) time solution using
and
concepts.
- Construct Segment Tree for RangeMinimumQuery and RangeMaximumQuery for the given input array.
- Take two pointers start and end, and initialize both to 0.
-
While end is less than the length of the input array, do the following:
- Find min and max in the current window using Segment Trees constructed in step 1.
- Check if 2 * min ≤ max, if so then increment start pointer else update max valid length so far, if required
- Increment end
- length(arr[]) – maxValidLength is the required answer.
Below is the implementation of the above approach:
#include <iostream> #include <vector> #include <cmath> #include <bits/stdc++.h> using namespace std;
class GFG {
public :
int removeMinElements(vector< int >& a) {
int n = a.size();
RangeMinimumQuery rMimQ;
vector< int > minTree = rMimQ.createSegmentTree(a);
RangeMaximumQuery rMaxQ;
vector< int > maxTree = rMaxQ.createSegmentTree(a);
int start = 0;
int end = 0;
// To store min and max in the current window
int min_val = 0;
int max_val = 0;
int maxValidLen = 0;
while (end < n) {
min_val = rMimQ.rangeMinimumQuery(minTree, start, end, n);
max_val = rMaxQ.rangeMaximumQuery(maxTree, start, end, n);
if (2 * min_val <= max_val)
start++;
else
maxValidLen = max(maxValidLen, end - start + 1);
end++;
}
return n - maxValidLen;
}
class RangeMinimumQuery {
public :
vector< int > createSegmentTree(vector< int >& input) {
int n = input.size();
int segTreeSize = 2 * get_next_power_of_two(n) - 1;
vector< int > segmentTree(segTreeSize, 0);
createSegmentTreeUtil(segmentTree, input, 0, n - 1, 0);
return segmentTree;
}
void createSegmentTreeUtil(vector< int >& segmentTree, vector< int >& input, int low, int high, int pos) {
if (low == high) {
// It's a leaf node
segmentTree[pos] = input[low];
return ;
}
// Construct left and right subtrees and then
// update value for the current node
int mid = (low + high) / 2;
createSegmentTreeUtil(segmentTree, input, low, mid, (2 * pos + 1));
createSegmentTreeUtil(segmentTree, input, mid + 1, high, (2 * pos + 2));
segmentTree[pos] = min(segmentTree[2 * pos + 1], segmentTree[2 * pos + 2]);
}
int rangeMinimumQuery(vector< int >& segmentTree, int from, int to, int inputSize) {
return rangeMinimumQueryUtil(segmentTree, 0, inputSize - 1, from, to, 0);
}
int rangeMinimumQueryUtil(vector< int >& segmentTree, int low, int high, int from, int to, int pos) {
// Total overlap
if (from <= low && to >= high) {
return segmentTree[pos];
}
// No overlap
if (from > high || to < low) {
return INT_MAX;
}
// Partial overlap
int mid = (low + high) / 2;
int left = rangeMinimumQueryUtil(segmentTree, low, mid, from, to, (2 * pos + 1));
int right = rangeMinimumQueryUtil(segmentTree, mid + 1, high, from, to, (2 * pos + 2));
return min(left, right);
}
private :
int get_next_power_of_two( int n) {
int logPart = ceil (log2(n));
return pow (2, logPart);
}
};
class RangeMaximumQuery {
public :
vector< int > createSegmentTree(vector< int >& input) {
int n = input.size();
int segTreeSize = 2 * get_next_power_of_two(n) - 1;
vector< int > segmentTree(segTreeSize, 0);
createSegmentTreeUtil(segmentTree, input, 0, n - 1, 0);
return segmentTree;
}
void createSegmentTreeUtil(vector< int >& segmentTree, vector< int >& input, int low, int high, int pos) {
if (low == high) {
// It's a leaf node
segmentTree[pos] = input[low];
return ;
}
// Construct left and right subtrees and then
// update value for the current node
int mid = (low + high) / 2;
createSegmentTreeUtil(segmentTree, input, low, mid, (2 * pos + 1));
createSegmentTreeUtil(segmentTree, input, mid + 1, high, (2 * pos + 2));
segmentTree[pos] = max(segmentTree[2 * pos + 1], segmentTree[2 * pos + 2]);
}
int rangeMaximumQuery(vector< int >& segmentTree, int from, int to, int inputSize) {
return rangeMaximumQueryUtil(segmentTree, 0, inputSize - 1, from, to, 0);
}
int rangeMaximumQueryUtil(vector< int >& segmentTree, int low, int high, int from, int to, int pos) {
// Total overlap
if (from <= low && to >= high) {
return segmentTree[pos];
}
// No overlap
if (from > high || to < low) {
return INT_MIN;
}
// Partial overlap
int mid = (low + high) / 2;
int left = rangeMaximumQueryUtil(segmentTree, low, mid, from, to, (2 * pos + 1));
int right = rangeMaximumQueryUtil(segmentTree, mid + 1, high, from, to, (2 * pos + 2));
return max(left, right);
}
private :
int get_next_power_of_two( int n) {
int logPart = ceil (log2(n));
return pow (2, logPart);
}
};
}; int main() {
vector< int > a = {4, 5, 100, 9, 10, 11, 12, 15, 200};
GFG gfg;
cout << gfg.removeMinElements(a) << endl;
return 0;
} |
// Java implementation of the approach public class GFG {
// Function to return the minimum removals
// required so that the array satisfy
// the given condition
public int removeMinElements( int [] a)
{
int n = a.length;
RangeMinimumQuery rMimQ = new RangeMinimumQuery();
int [] minTree = rMimQ.createSegmentTree(a);
RangeMaximumQuery rMaxQ = new RangeMaximumQuery();
int [] maxTree = rMaxQ.createSegmentTree(a);
int start = 0 , end = 0 ;
// To store min and max in the current window
int min, max;
int maxValidLen = 0 ;
while (end < n) {
min = rMimQ.rangeMinimumQuery(minTree,
start, end, n);
max = rMaxQ.rangeMaximumQuery(maxTree,
start, end, n);
if ( 2 * min <= max)
start++;
else
maxValidLen = Math.max(maxValidLen,
end - start + 1 );
end++;
}
return n - maxValidLen;
}
class RangeMinimumQuery {
// Creates a new segment tree from
// the given input array
public int [] createSegmentTree( int [] input)
{
int n = input.length;
int segTreeSize = 2 * getNextPowerOfTwo(n) - 1 ;
int [] segmentTree = new int [segTreeSize];
createSegmentTreeUtil(segmentTree, input,
0 , n - 1 , 0 );
return segmentTree;
}
private void createSegmentTreeUtil( int [] segmentTree,
int [] input, int low,
int high, int pos)
{
if (low == high) {
// Its a leaf node
segmentTree[pos] = input[low];
return ;
}
// Construct left and right subtrees and then
// update value for current node
int mid = (low + high) / 2 ;
createSegmentTreeUtil(segmentTree, input, low,
mid, ( 2 * pos + 1 ));
createSegmentTreeUtil(segmentTree, input,
mid + 1 , high, ( 2 * pos + 2 ));
segmentTree[pos] = Math.min(segmentTree[ 2 * pos + 1 ],
segmentTree[ 2 * pos + 2 ]);
}
public int rangeMinimumQuery( int [] segmentTree, int from,
int to, int inputSize)
{
return rangeMinimumQueryUtil(segmentTree, 0 ,
inputSize - 1 , from, to, 0 );
}
private int rangeMinimumQueryUtil( int [] segmentTree, int low,
int high, int from, int to, int pos)
{
// Total overlap
if (from <= low && to >= high) {
return segmentTree[pos];
}
// No overlap
if (from > high || to < low) {
return Integer.MAX_VALUE;
}
// Partial overlap
int mid = (low + high) / 2 ;
int left = rangeMinimumQueryUtil(segmentTree, low,
mid, from, to,
( 2 * pos + 1 ));
int right = rangeMinimumQueryUtil(segmentTree,
mid + 1 , high, from,
to, ( 2 * pos + 2 ));
return Math.min(left, right);
}
}
class RangeMaximumQuery {
// Creates a new segment tree from given input array
public int [] createSegmentTree( int [] input)
{
int n = input.length;
int segTreeSize = 2 * getNextPowerOfTwo(n) - 1 ;
int [] segmentTree = new int [segTreeSize];
createSegmentTreeUtil(segmentTree, input, 0 , n - 1 , 0 );
return segmentTree;
}
private void createSegmentTreeUtil( int [] segmentTree, int [] input,
int low, int high, int pos)
{
if (low == high) {
// Its a leaf node
segmentTree[pos] = input[low];
return ;
}
// Construct left and right subtrees and then
// update value for current node
int mid = (low + high) / 2 ;
createSegmentTreeUtil(segmentTree, input, low,
mid, ( 2 * pos + 1 ));
createSegmentTreeUtil(segmentTree, input,
mid + 1 , high, ( 2 * pos + 2 ));
segmentTree[pos] = Math.max(segmentTree[ 2 * pos + 1 ],
segmentTree[ 2 * pos + 2 ]);
}
public int rangeMaximumQuery( int [] segmentTree,
int from, int to, int inputSize)
{
return rangeMaximumQueryUtil(segmentTree, 0 ,
inputSize - 1 , from, to, 0 );
}
private int rangeMaximumQueryUtil( int [] segmentTree, int low,
int high, int from, int to, int pos)
{
// Total overlap
if (from <= low && to >= high) {
return segmentTree[pos];
}
// No overlap
if (from > high || to < low) {
return Integer.MIN_VALUE;
}
// Partial overlap
int mid = (low + high) / 2 ;
int left = rangeMaximumQueryUtil(segmentTree, low,
mid, from, to,
( 2 * pos + 1 ));
int right = rangeMaximumQueryUtil(segmentTree,
mid + 1 , high, from,
to, ( 2 * pos + 2 ));
return Math.max(left, right);
}
}
// Function to return the minimum power of 2
// which is greater than n
private int getNextPowerOfTwo( int n)
{
int logPart = ( int )Math.ceil(Math.log(n)
/ Math.log( 2 ));
return ( int )Math.pow( 2 , logPart);
}
// Driver code
public static void main(String[] args)
{
int [] a = { 4 , 5 , 100 , 9 , 10 , 11 , 12 , 15 , 200 };
GFG gfg = new GFG();
System.out.println(gfg.removeMinElements(a));
}
} |
import math
class GFG:
# Function to return the minimum removals
# required so that the array satisfies
# the given condition
def removeMinElements( self , a):
n = len (a)
rMimQ = self .RangeMinimumQuery()
minTree = rMimQ.createSegmentTree(a)
rMaxQ = self .RangeMaximumQuery()
maxTree = rMaxQ.createSegmentTree(a)
start = 0
end = 0
# To store min and max in the current window
min_val = 0
max_val = 0
maxValidLen = 0
while end < n:
min_val = rMimQ.rangeMinimumQuery(minTree, start, end, n)
max_val = rMaxQ.rangeMaximumQuery(maxTree, start, end, n)
if 2 * min_val < = max_val:
start + = 1
else :
maxValidLen = max (maxValidLen, end - start + 1 )
end + = 1
return n - maxValidLen
class RangeMinimumQuery:
def createSegmentTree( self , input ):
n = len ( input )
segTreeSize = 2 * self .get_next_power_of_two(n) - 1
segmentTree = [ 0 ] * segTreeSize
self .createSegmentTreeUtil(segmentTree, input , 0 , n - 1 , 0 )
return segmentTree
def createSegmentTreeUtil( self , segmentTree, input , low, high, pos):
if low = = high:
# It's a leaf node
segmentTree[pos] = input [low]
return
# Construct left and right subtrees and then
# update value for the current node
mid = (low + high) / / 2
self .createSegmentTreeUtil(segmentTree, input , low, mid, ( 2 * pos + 1 ))
self .createSegmentTreeUtil(segmentTree, input , mid + 1 , high, ( 2 * pos + 2 ))
segmentTree[pos] = min (segmentTree[ 2 * pos + 1 ], segmentTree[ 2 * pos + 2 ])
def rangeMinimumQuery( self , segmentTree, from_, to, inputSize):
return self .rangeMinimumQueryUtil(segmentTree, 0 , inputSize - 1 , from_, to, 0 )
def rangeMinimumQueryUtil( self , segmentTree, low, high, from_, to, pos):
# Total overlap
if from_ < = low and to > = high:
return segmentTree[pos]
# No overlap
if from_ > high or to < low:
return float ( 'inf' )
# Partial overlap
mid = (low + high) / / 2
left = self .rangeMinimumQueryUtil(segmentTree, low, mid, from_, to, ( 2 * pos + 1 ))
right = self .rangeMinimumQueryUtil(segmentTree, mid + 1 , high, from_, to, ( 2 * pos + 2 ))
return min (left, right)
# Move the get_next_power_of_two method here
def get_next_power_of_two( self , n):
log_part = math.ceil(math.log(n) / math.log( 2 ))
return 2 * * log_part
class RangeMaximumQuery:
# Move the get_next_power_of_two method here
def get_next_power_of_two( self , n):
log_part = math.ceil(math.log(n) / math.log( 2 ))
return 2 * * log_part
def createSegmentTree( self , input ):
n = len ( input )
segTreeSize = 2 * self .get_next_power_of_two(n) - 1
segmentTree = [ 0 ] * segTreeSize
self .createSegmentTreeUtil(segmentTree, input , 0 , n - 1 , 0 )
return segmentTree
def createSegmentTreeUtil( self , segmentTree, input , low, high, pos):
if low = = high:
# It's a leaf node
segmentTree[pos] = input [low]
return
# Construct left and right subtrees and then
# update value for the current node
mid = (low + high) / / 2
self .createSegmentTreeUtil(segmentTree, input , low, mid, ( 2 * pos + 1 ))
self .createSegmentTreeUtil(segmentTree, input , mid + 1 , high, ( 2 * pos + 2 ))
segmentTree[pos] = max (segmentTree[ 2 * pos + 1 ], segmentTree[ 2 * pos + 2 ])
def rangeMaximumQuery( self , segmentTree, from_, to, inputSize):
return self .rangeMaximumQueryUtil(segmentTree, 0 , inputSize - 1 , from_, to, 0 )
def rangeMaximumQueryUtil( self , segmentTree, low, high, from_, to, pos):
# Total overlap
if from_ < = low and to > = high:
return segmentTree[pos]
# No overlap
if from_ > high or to < low:
return float ( '-inf' )
# Partial overlap
mid = (low + high) / / 2
left = self .rangeMaximumQueryUtil(segmentTree, low, mid, from_, to, ( 2 * pos + 1 ))
right = self .rangeMaximumQueryUtil(segmentTree, mid + 1 , high, from_, to, ( 2 * pos + 2 ))
return max (left, right)
# Driver code if __name__ = = "__main__" :
a = [ 4 , 5 , 100 , 9 , 10 , 11 , 12 , 15 , 200 ]
gfg = GFG()
print (gfg.removeMinElements(a))
|
// C# implementation of the approach using System;
class GFG
{ // Function to return the minimum removals
// required so that the array satisfy
// the given condition
static int removeMinElements( int [] a)
{
int n = a.Length;
RangeMinimumQuery rMimQ = new RangeMinimumQuery();
int [] minTree = rMimQ.createSegmentTree(a);
RangeMaximumQuery rMaxQ = new RangeMaximumQuery();
int [] maxTree = rMaxQ.createSegmentTree(a);
int start = 0, end = 0;
// To store min and max in the current window
int min, max;
int maxValidLen = 0;
while (end < n)
{
min = rMimQ.rangeMinimumQuery(minTree,
start, end, n);
max = rMaxQ.rangeMaximumQuery(maxTree,
start, end, n);
if (2 * min <= max)
start++;
else
maxValidLen = Math.Max(maxValidLen,
end - start + 1);
end++;
}
return n - maxValidLen;
}
class RangeMinimumQuery {
// Creates a new segment tree from
// the given input array
public int [] createSegmentTree( int [] input)
{
int n = input.Length;
int segTreeSize = 2 * getNextPowerOfTwo(n) - 1;
int [] segmentTree = new int [segTreeSize];
createSegmentTreeUtil(segmentTree, input,
0, n - 1, 0);
return segmentTree;
}
public void createSegmentTreeUtil( int [] segmentTree,
int [] input, int low,
int high, int pos)
{
if (low == high) {
// Its a leaf node
segmentTree[pos] = input[low];
return ;
}
// Construct left and right subtrees and then
// update value for current node
int mid = (low + high) / 2;
createSegmentTreeUtil(segmentTree, input, low,
mid, (2 * pos + 1));
createSegmentTreeUtil(segmentTree, input,
mid + 1, high, (2 * pos + 2));
segmentTree[pos] = Math.Min(segmentTree[2 * pos + 1],
segmentTree[2 * pos + 2]);
}
public int rangeMinimumQuery( int [] segmentTree, int from ,
int to, int inputSize)
{
return rangeMinimumQueryUtil(segmentTree, 0,
inputSize - 1, from , to, 0);
}
static int rangeMinimumQueryUtil( int [] segmentTree, int low,
int high, int from , int to, int pos)
{
// Total overlap
if ( from <= low && to >= high) {
return segmentTree[pos];
}
// No overlap
if ( from > high || to < low) {
return int .MaxValue;
}
// Partial overlap
int mid = (low + high) / 2;
int left = rangeMinimumQueryUtil(segmentTree, low,
mid, from , to,
(2 * pos + 1));
int right = rangeMinimumQueryUtil(segmentTree,
mid + 1, high, from ,
to, (2 * pos + 2));
return Math.Min(left, right);
}
}
class RangeMaximumQuery {
// Creates a new segment tree from given input array
public int [] createSegmentTree( int [] input)
{
int n = input.Length;
int segTreeSize = 2 * getNextPowerOfTwo(n) - 1;
int [] segmentTree = new int [segTreeSize];
createSegmentTreeUtil(segmentTree, input, 0, n - 1, 0);
return segmentTree;
}
public void createSegmentTreeUtil( int [] segmentTree, int [] input,
int low, int high, int pos)
{
if (low == high) {
// Its a leaf node
segmentTree[pos] = input[low];
return ;
}
// Construct left and right subtrees and then
// update value for current node
int mid = (low + high) / 2;
createSegmentTreeUtil(segmentTree, input, low,
mid, (2 * pos + 1));
createSegmentTreeUtil(segmentTree, input,
mid + 1, high, (2 * pos + 2));
segmentTree[pos] = Math.Max(segmentTree[2 * pos + 1],
segmentTree[2 * pos + 2]);
}
public int rangeMaximumQuery( int [] segmentTree,
int from , int to, int inputSize)
{
return rangeMaximumQueryUtil(segmentTree, 0,
inputSize - 1, from , to, 0);
}
public int rangeMaximumQueryUtil( int [] segmentTree, int low,
int high, int from , int to, int pos)
{
// Total overlap
if ( from <= low && to >= high) {
return segmentTree[pos];
}
// No overlap
if ( from > high || to < low) {
return int .MinValue;
}
// Partial overlap
int mid = (low + high) / 2;
int left = rangeMaximumQueryUtil(segmentTree, low,
mid, from , to,
(2 * pos + 1));
int right = rangeMaximumQueryUtil(segmentTree,
mid + 1, high, from ,
to, (2 * pos + 2));
return Math.Max(left, right);
}
}
// Function to return the minimum power of 2
// which is greater than n
static int getNextPowerOfTwo( int n)
{
int logPart = ( int )Math.Ceiling(Math.Log(n)
/ Math.Log(2));
return ( int )Math.Pow(2, logPart);
}
// Driver code
public static void Main(String[] args)
{
int [] a = { 4, 5, 100, 9, 10, 11, 12, 15, 200 };
Console.WriteLine(removeMinElements(a));
}
} // This code is contributed by Rajput-Ji |
class GFG { removeMinElements(a) {
const n = a.length;
// Create RangeMinimumQuery object
const rMimQ = new RangeMinimumQuery();
const minTree = rMimQ.createSegmentTree(a);
// Create RangeMaximumQuery object
const rMaxQ = new RangeMaximumQuery();
const maxTree = rMaxQ.createSegmentTree(a);
let start = 0;
let end = 0;
// To store min and max in the current window
let min_val = 0;
let max_val = 0;
let maxValidLen = 0;
while (end < n) {
min_val = rMimQ.rangeMinimumQuery(minTree, start, end, n);
max_val = rMaxQ.rangeMaximumQuery(maxTree, start, end, n);
if (2 * min_val <= max_val) start++;
else maxValidLen = Math.max(maxValidLen, end - start + 1);
end++;
}
return n - maxValidLen;
}
} class RangeMinimumQuery { createSegmentTree(input) {
const n = input.length;
const segTreeSize = 2 * this .getNextPowerOfTwo(n) - 1;
const segmentTree = Array(segTreeSize).fill(0);
this .createSegmentTreeUtil(segmentTree, input, 0, n - 1, 0);
return segmentTree;
}
createSegmentTreeUtil(segmentTree, input, low, high, pos) {
if (low === high) {
// It's a leaf node
segmentTree[pos] = input[low];
return ;
}
// Construct left and right subtrees and then
// update value for the current node
const mid = Math.floor((low + high) / 2);
this .createSegmentTreeUtil(segmentTree, input, low, mid, 2 * pos + 1);
this .createSegmentTreeUtil(segmentTree, input, mid + 1, high, 2 * pos + 2);
segmentTree[pos] = Math.min(segmentTree[2 * pos + 1], segmentTree[2 * pos + 2]);
}
rangeMinimumQuery(segmentTree, from, to, inputSize) {
return this .rangeMinimumQueryUtil(segmentTree, 0, inputSize - 1, from, to, 0);
}
rangeMinimumQueryUtil(segmentTree, low, high, from, to, pos) {
// Total overlap
if (from <= low && to >= high) {
return segmentTree[pos];
}
// No overlap
if (from > high || to < low) {
return Infinity;
}
// Partial overlap
const mid = Math.floor((low + high) / 2);
const left = this .rangeMinimumQueryUtil(segmentTree, low, mid, from, to, 2 * pos + 1);
const right = this .rangeMinimumQueryUtil(segmentTree, mid + 1, high, from, to, 2 * pos + 2);
return Math.min(left, right);
}
getNextPowerOfTwo(n) {
const logPart = Math.ceil(Math.log2(n));
return 2 ** logPart;
}
} class RangeMaximumQuery { createSegmentTree(input) {
const n = input.length;
const segTreeSize = 2 * this .getNextPowerOfTwo(n) - 1;
const segmentTree = Array(segTreeSize).fill(0);
this .createSegmentTreeUtil(segmentTree, input, 0, n - 1, 0);
return segmentTree;
}
createSegmentTreeUtil(segmentTree, input, low, high, pos) {
if (low === high) {
// It's a leaf node
segmentTree[pos] = input[low];
return ;
}
// Construct left and right subtrees and then
// update value for the current node
const mid = Math.floor((low + high) / 2);
this .createSegmentTreeUtil(segmentTree, input, low, mid, 2 * pos + 1);
this .createSegmentTreeUtil(segmentTree, input, mid + 1, high, 2 * pos + 2);
segmentTree[pos] = Math.max(segmentTree[2 * pos + 1], segmentTree[2 * pos + 2]);
}
rangeMaximumQuery(segmentTree, from, to, inputSize) {
return this .rangeMaximumQueryUtil(segmentTree, 0, inputSize - 1, from, to, 0);
}
rangeMaximumQueryUtil(segmentTree, low, high, from, to, pos) {
// Total overlap
if (from <= low && to >= high) {
return segmentTree[pos];
}
// No overlap
if (from > high || to < low) {
return -Infinity;
}
// Partial overlap
const mid = Math.floor((low + high) / 2);
const left = this .rangeMaximumQueryUtil(segmentTree, low, mid, from, to, 2 * pos + 1);
const right = this .rangeMaximumQueryUtil(segmentTree, mid + 1, high, from, to, 2 * pos + 2);
return Math.max(left, right);
}
getNextPowerOfTwo(n) {
const logPart = Math.ceil(Math.log2(n));
return 2 ** logPart;
}
} const gfg = new GFG();
const a = [4, 5, 100, 9, 10, 11, 12, 15, 200]; console.log(gfg.removeMinElements(a)); |
4