【问题标题】:Find elements which need to be removed from an array such that 2*min>max查找需要从数组中删除的元素,使得 2*min>max
【发布时间】:2014-05-26 22:30:28
【问题描述】:

考虑以下问题:

给出一个整数数组。您的目标是修剪数组,使 2*min > max,其中 min 和 max 是数组的最小和最大元素。如果上述条件不满足,您可以从数组的开头或结尾删除元素。应尽量减少移除次数。

例如如果数组是

a, b, c, d, e, f

其中 c 是最小值,e 是最大值,那么如果 2*c > e 为真,我们就完成了。如果不是,我们可以从开头(即 a、b、c)或从结尾(即 e、f)删除,这样新的 min 或 max 将满足条件并且删除应该是最小的。

我有一个 O(n2) 算法来解决这个问题。这能在 O(n log n) 的时间内解决吗?

【问题讨论】:

  • 你的 O(n^2) 算法是什么?
  • 嗯,你也可以同时从两边移除吗?否则我的回答比必要的更笼统

标签: arrays algorithm big-o time-complexity


【解决方案1】:

请注意,问题是找到满足条件的最大子数组。意识到如果条件对一个索引区间成立,它也适用于其中包含的所有区间。所以如果我们固定一个边界,我们可以贪婪地选择尽可能远离它的另一个边界。

可以在线性时间内解决这个问题:

如果您选择元素 i 作为左边界,则将 ri 定义为最右边的可能右边界。我们可以证明ri中是单调的,所以我们可以维护两个指向iri的指针sub> 并在每次将 i 递增 1 后尽可能地递增 ri。两个指针总共增加了 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) 是否满足)。

之所以有效,是因为谓词“范围满足条件”在包含方面是单调的(如果一个范围满足它,那么它所包含的所有范围也都满足它)。

【讨论】:

    【解决方案2】:

    你能改变数组中元素的顺序吗? 如果是这样,您可以执行以下步骤:

    1. 使用例如快速排序或任何最适合的方式对数组进行排序 你的要求 -> O(n lg n)
    2. 取第一个键 k = 2*input[0] -> O(1)
    3. 使用二分查找算法查找键k在数组中的索引-> O(lg n)
    4. 如果找到的索引大于输入数组长度的一半,则删除数组的最后一部分,否则删除第一部分。 -> O(1)

    在这种情况下,复杂度是 O(n ln n) + O(1) + O(lg n) + O(1) => O(n lg n) 的总和

    【讨论】:

    • 你的算法对于这个输入是错误的 .. 2 3 3 4 5 6 ... ans 应该是 1 但你的算法给出了 ans=2。
    猜你喜欢
    • 1970-01-01
    • 2017-06-30
    • 1970-01-01
    • 1970-01-01
    • 2018-05-21
    • 1970-01-01
    • 1970-01-01
    • 2017-09-25
    • 2022-06-10
    相关资源
    最近更新 更多