Given an array arr, the task is to remove minimum number of elements such that after their removal, max(arr) <= 2 * min(arr).
Examples:
Input: arr[] = {4, 5, 3, 8, 3}
Output: 1 Remove 8 from the array.Input: arr[] = {1, 2, 3, 4}
Output: 1 Remove 1 from the array.
Approach: Let us fix each value as the minimum value say x and find number of terms that are in range [x, 2*x]. This can be done using prefix-sums, we can use map (implements self balancing BST) instead of array as the values can be large. The remaining terms which are not in range [x, 2*x] will have to be removed. So, across all values of x, we choose the one which maximises the number of terms in range [x, 2*x].
Below is the implementation of the above approach:
// C++ implementation of the approach #include <bits/stdc++.h> using namespace std;
// Function to return the minimum removals from // arr such that max(arr) <= 2 * min(arr) int minimumRemovals( int n, int a[])
{ // Count occurrence of each element
map< int , int > ct;
for ( int i = 0; i < n; i++)
ct[a[i]]++;
// Take prefix sum
int sm = 0;
for ( auto mn : ct) {
sm += mn.second;
ct[mn.first] = sm;
}
int mx = 0, prev = 0;
for ( auto mn : ct) {
// Chosen minimum
int x = mn.first;
int y = 2 * x;
auto itr = ct.upper_bound(y);
itr--;
// Number of elements that are in
// range [x, 2x]
int cr = (itr->second) - prev;
mx = max(mx, cr);
prev = mn.second;
}
// Minimum elements to be removed
return n - mx;
} // Driver Program to test above function int main()
{ int arr[] = { 4, 5, 3, 8, 3 };
int n = sizeof (arr) / sizeof (arr[0]);
cout << minimumRemovals(n, arr);
return 0;
} |
// Java implementation of the approach import java.util.*;
public class Main {
// Function to return the minimum removals from
// arr such that max(arr) <= 2 * min(arr)
public static int minimumRemovals( int n, int [] a) {
// Count occurrence of each element
Map<Integer, Integer> ct = new HashMap<>();
for ( int i = 0 ; i < n; i++) {
ct.put(a[i], ct.getOrDefault(a[i], 0 ) + 1 );
}
// Take prefix sum
int sm = 0 ;
for ( int mn : ct.keySet()) {
sm += ct.get(mn);
ct.put(mn, sm);
}
int mx = 0 , prev = 0 ;
for ( int mn : ct.keySet()) {
// Chosen minimum
int x = mn;
int y = 2 * x;
List<Integer> keysList = new ArrayList<>(ct.keySet());
int index = Collections.binarySearch(keysList, y);
int pos = index >= 0 ? index : -(index + 1 ) - 1 ;
Integer itr = pos >= 0 ? ct.get(keysList.get(pos)) : null ;
// Number of elements that are in
// range [x, 2x]
int cr = (itr != null ? itr : 0 ) - prev;
mx = Math.max(mx, cr);
prev = ct.get(mn);
}
// Minimum elements to be removed
return n - mx;
}
// Driver Program to test above function
public static void main(String[] args) {
int [] arr = { 4 , 5 , 3 , 8 , 3 };
int n = arr.length;
System.out.println(minimumRemovals(n, arr));
}
} // This code is contributed by codebraxnzt |
# Python3 implementation of the approach from bisect import bisect_left as upper_bound
# Function to return the minimum removals from # arr such that max(arr) <= 2 * min(arr) def minimumRemovals(n, a):
# Count occurrence of each element
ct = dict ()
for i in a:
ct[i] = ct.get(i, 0 ) + 1
# Take prefix sum
sm = 0
for mn in ct:
sm + = ct[mn]
ct[mn] = sm
mx = 0
prev = 0 ;
for mn in ct:
# Chosen minimum
x = mn
y = 2 * x
itr = upper_bound( list (ct), y)
# Number of elements that are in
# range [x, 2x]
cr = ct[itr] - prev
mx = max (mx, cr)
prev = ct[mn]
# Minimum elements to be removed
return n - mx
# Driver Code arr = [ 4 , 5 , 3 , 8 , 3 ]
n = len (arr)
print (minimumRemovals(n, arr))
# This code is contributed by Mohit Kumar |
// C# program for the above approach using System;
using System.Collections.Generic;
public class MainClass
{ // Function to return the minimum removals from
// arr such that max(arr) <= 2 * min(arr)
public static int minimumRemovals( int n, int [] a)
{
// Count occurrence of each element
Dictionary< int , int > ct = new Dictionary< int , int >();
for ( int i = 0; i < n; i++)
{
if (ct.ContainsKey(a[i]))
{
ct[a[i]]++;
}
else
{
ct[a[i]] = 1;
}
}
// Take prefix sum
int sm = 0;
List< int > keysList = new List< int >(ct.Keys);
keysList.Sort();
foreach ( int mn in keysList)
{
sm += ct[mn];
ct[mn] = sm;
}
int mx = 0, prev = 0;
foreach ( int mn in keysList)
{
// Chosen minimum
int x = mn;
int y = 2 * x;
int index = keysList.BinarySearch(y);
int pos = index >= 0 ? index : -(index + 1) - 1;
int itr = pos >= 0 ? ct[keysList[pos]] : 0;
// Number of elements that are in
// range [x, 2x]
int cr = itr - prev;
mx = Math.Max(mx, cr);
prev = ct[mn];
}
// Minimum elements to be removed
return n - mx;
}
// Driver Program to test above function
public static void Main()
{
int [] arr = { 4, 5, 3, 8, 3 };
int n = arr.Length;
Console.WriteLine(minimumRemovals(n, arr));
}
} // This code is contributed by Prince Kumar |
// JavaScript implementation of the approach // Function to return the minimum removals from arr such that max(arr) <= 2 * min(arr) function minimumRemovals(n, a){
// Import upper_bound from bisect
const upper_bound = (arr, x) => {
let low = 0, high = arr.length;
while (low < high) {
const mid = (low + high) >>> 1;
if (x >= arr[mid]) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
// Count occurrence of each element
let ct = new Map();
for (let i of a){
ct.set(i, (ct.get(i) || 0) + 1);
}
// Take prefix sum
let sm = 0;
for (let mn of ct.keys()){
sm += ct.get(mn);
ct.set(mn, sm);
}
let mx = 0;
let prev = 0;
for (let mn of ct.keys()){
// Chosen minimum
let x = mn;
let y = 2 * x;
let itr = upper_bound(Array.from(ct.keys()), y);
// Number of elements that are in range [x, 2x]
let cr = ct.get([...ct.keys()][itr-1]) - ct.get(mn) + prev;
mx = Math.max(mx, cr);
prev = ct.get(mn) - (ct.get(mn - 1) || 0);
}
// Minimum elements to be removed
return n - mx;
} // Driver Code let arr = [4, 5, 3, 8, 3]; let n = arr.length; console.log(minimumRemovals(n, arr)); // This code is contributed by princekumaras |
1