【问题标题】:selection algorithm problem选择算法问题
【发布时间】:2011-05-04 22:54:23
【问题描述】:

假设你有一个包含 n 个项目的数组 A,并且你想找到 A 中最接近的 k 个项目 到 A 的中位数。例如,如果 A 包含 9 个值 {7, 14, 10, 12, 2, 11, 29, 3, 4} 和 k = 5,那么答案将是值 {7, 14, 10, 12, 11},因为中位数 是 10,这些是 A 中最接近值 10 的五个值。给出一个算法 在 O(n) 时间内解决这个问题。

我知道选择算法(深度选择)是解决这个问题的合适算法,但我认为它会在 O(n*logn) 时间而不是 O(n) 时间内运行。任何帮助将不胜感激:)

【问题讨论】:

  • IMO 你必须对列表进行排序,而且总是大于 O(n)。
  • 您的问题相当于能够在 O(n) 时间内找到任意百分位数。在 O(n) 时间内找到 just 中位数(即解决 k = 1 的问题)是可能的,但并非易事。该算法可能可以扩展到找到百分位数。你为什么需要这个?是作业吗?

标签: algorithm selection


【解决方案1】:

您首先需要找到中位数,这可以在 O(n) 中完成(例如使用 Hoare 的 Quickselect 算法)。

然后您将需要实现一种排序算法,该算法根据元素与中位数的绝对距离(首先是最小距离)对数组中的元素进行排序。

如果您要以这种方式对整个数组进行排序,这通常需要从O(n * log n)O(n^2),具体取决于所使用的算法。但是,由于您只需要第一个 k 值,因此可以将复杂性降低到 O(k * log n)O(k * n)

由于k 是一个常数并且不依赖于数组的大小,因此最坏情况下的总体复杂度将为:O(n)(用于查找中位数)+O(k * n)(排序),即总体上是O(n)

【讨论】:

【解决方案2】:

我认为您可以使用快速排序的变体来做到这一点。

您从一组包含 n 个项目的 S 开始,并正在寻找“中间”k 个项目。您可以将其视为将 S 划分为大小为 n - k/2(“下”项目)、k(“中”项目)和 n - k/2(“上”项目)的三部分。

这给了我们一个策略:首先从 S 中移除较低的 n - k/2 个项目,留下 S'。然后从S'中去掉上面的n-k/2项,留下S'',也就是S的中间k项。

您可以使用“半快速排序”轻松地对集合进行分区:选择一个枢轴,将集合划分为 L 和 U(枢轴的上下元素),然后您知道要在分区中丢弃的项目必须要么是 L 的全部,要么是 U 的一部分,反之亦然:相应地递归。

[进一步思考,如果您以其他方式定义“最接近中位数”,这可能不是您想要的,但这是一个开始。]

【讨论】:

    【解决方案3】:

    假设:我们关心 A 中最接近中位数的 k 个值。如果我们有 A={1,2,2,2,2,2,2,2,2,2,2,2,3},k=3,答案是 {2,2,2}。同样,如果我们有 A={0,1,2,3,3,4,5,6} 和 k=3,则答案 {2,3,3} 和 {3,3,4} 同样有效。此外,我们对这些值来自的索引不感兴趣,尽管我认为对算法进行一些小的调整会起作用。

    1. 正如 Grodrigues 所说,首先在 O(n) 时间内找到中位数。当我们这样做时,请跟踪最大和最小的数字
    2. 接下来,创建一个数组 K,k 项长。该数组将包含项目与中位数的距离。 (请注意,
    3. 将前 k 项从 A 复制到 K。
    4. 对于每个项目 A[i],比较 A[i] 从中位数到 K 中每个项目的距离。如果 A[i] 比离中位数最远的项目更接近中位数,则替换为物品。作为一种优化,我们还可以跟踪 K 与中位数最近和最远的项目,因此我们可以更快地与 K 进行比较,或者我们可以保持 K 排序,但是这两种优化都不需要在 O(n) 时间内运行。

    伪代码,C++ ish:

    /* n = 数组长度 * 数组 = A,问题中给出 * result 是一个预分配的数组,将放置结果 * k 是结果的长度 * * 返回 * 0 表示成功 * -1 无效输入 * 1 表示其他错误 * * 实施说明:跳过优化。 */ #定义成功 0 #define INVALID_INPUT -1 #定义错误 1 void find_k_closest(int n, int[] 数组, int k, int[] 结果) { // 如果我们正在寻找比可能更多的结果, // 不可能给出有效的结果。 if( k > n ) 返回无效输入; // 使用数组的前 k 个元素填充结果。 for(int i=0;iabs(b)) ? 1 : 0; 内在: for( int i=1; i

    【讨论】:

      猜你喜欢
      • 2011-12-10
      • 2018-07-18
      • 1970-01-01
      • 2015-02-07
      • 1970-01-01
      • 2011-11-09
      • 1970-01-01
      • 2018-08-25
      相关资源
      最近更新 更多