给定一个未排序的数组,对数组进行修剪,以使最小值的两倍大于修剪后的数组中的最大值。元素应从数组的任一端删除。清除次数应最少。
例子:
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
方法:在上一篇文章中,我们讨论了在O(n 3 ),O(n 2 * logn)和O(n 2 )时间中解决此问题的各种方法。在本文中,我们将讨论使用滑动窗口和分段树概念的O(n * logn)时间解决方案。
- 为给定输入数组的RangeMinimumQuery和RangeMaximumQuery构造细分树。
- 取两个指针start和end ,并将它们都初始化为0 。
- 当end小于输入数组的长度时,请执行以下操作:
- 使用第1步中构建的细分树在当前窗口中找到最小值和最大值。
- 检查是否2 * min≤max ,如果是,则递增起始指针,否则更新到目前为止的最大有效长度(如果需要)
- 增量结束
- length(arr [])– maxValidLength是必需的答案。
下面是上述方法的实现:
Java
// 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));
}
}
C#
// 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
输出:
4