📌  相关文章
📜  从任一侧移除最小元素,以使2 * min大于max |套装2

📅  最后修改于: 2021-04-17 10:48:35             🧑  作者: Mango

给定一个未排序的数组,对数组进行修剪,以使最小值的两倍大于修剪后的数组中的最大值。元素应从数组的任一端删除。清除次数应最少。

例子:

方法:在上一篇文章中,我们讨论了在O(n 3 ),O(n 2 * logn)和O(n 2 )时间中解决此问题的各种方法。在本文中,我们将讨论使用滑动窗口和分段树概念的O(n * logn)时间解决方案。

  1. 为给定输入数组的RangeMinimumQuery和RangeMaximumQuery构造细分树。
  2. 取两个指针startend ,并将它们都初始化为0
  3. end小于输入数组的长度时,请执行以下操作:
    • 使用第1步中构建的细分树在当前窗口中找到最小值最大值
    • 检查是否2 * min≤max ,如果是,则递增起始指针,否则更新到目前为止的最大有效长度(如果需要)
    • 增量结束
  4. 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