考虑以下问题:
给出了一个整数数组。你的目标是修剪阵列,使得2 * min> max,其中min和max是数组的最小和最大元素。如果上述条件不满足,您可以从数组的开头或结尾删除元素。删除次数应尽量减少。
例如,如果数组是
a, b, c, d, e, f
其中c是最小值,e是最大值,那么如果2 * c>是的,我们已经完成了。如果没有,我们可以从开始(即a,b,c)或从末尾(即e,f)移除,以便新的最小值或最大值满足条件,并且移除应该是最小的。
我有一个针对此问题的O(n 2 )算法。这可以在时间O(n log n)中解决吗?
答案 0 :(得分:5)
请注意,问题是找到满足条件的最大子阵列。实现如果条件适用于索引的间隔,它也适用于其中包含的所有间隔。因此,如果我们修复一个边界,我们可以贪婪地选择尽可能远离它的另一个边界。
可以在线性时间内解决这个问题:
如果选择元素 i 作为左边界,则将r i 定义为最右边的右边界。我们可以证明 r 在 i 中是单调的,所以我们可以保持两个指向 i 和 r i的指针在我们将 i 增加一次之后,每次使用sub> 并递增 r i 。两个指针总共递增O(n)次,并且我们可以使用范围中值的堆或二进制搜索树将每个增量的范围最小值/最大值维持在O(log n)。
使用monotonic queue我们可以在O(1)中维护极值并获得O(n)的总运行时间。例如,可以在here找到队列的另一个C ++实现。
另一种不太优雅的方式是使用RMQ data structure。它允许你在O(n log n)预处理之后查询O(1)范围内的最小值/最大值(O(n)预处理也是可能的,但这里复杂且不必要,因为算法的其余部分不是线性时间)。
现在修复左边框(有n种可能性)。使用二分搜索找到仍然满足条件的最右边界(你可以检查O(1)是否存在)。
这是因为谓词“范围满足条件”在包含方面是单调的(如果范围满足它,其中包含的所有范围也满足它)。
答案 1 :(得分:0)
您可以更改数组中元素的顺序吗? 如果是这样,您可以执行以下步骤:
在这种情况下,复杂度是O(n ln n)+ O(1)+ O(lg n)+ O(1)=>的总和。 O(n lg n)