Algorithm 选择算法问题

Algorithm 选择算法问题,algorithm,selection,Algorithm,Selection,假设您有一个由n个项目组成的数组,并且希望在最近的数组中查找k个项目 例如,如果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)。任何帮助都将不胜感激:)您首先需要找到中值,这可以在O(n)中完成(例如使用霍尔算法) 然后需要实

假设您有一个由n个项目组成的数组,并且希望在最近的数组中查找k个项目 例如,如果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)。任何帮助都将不胜感激:)

您首先需要找到中值,这可以在
O(n)
中完成(例如使用霍尔算法)

然后需要实现一个排序算法,该算法根据元素到中间值的绝对距离(首先是最小距离)对数组中的元素进行排序

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


由于
k
是一个常数,并且不取决于数组的大小,因此最坏情况下的总体复杂性将是:
O(n)
(用于查找中值)+
O(k*n)
(排序),这是
O(n)
总体上的复杂性。

我认为可以使用快速排序上的一个变量来实现这一点

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

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

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


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

假设:我们关心a中最接近中位数的k值。如果我们有A={1,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}同样有效。此外,我们对这些值来自的索引不感兴趣,尽管我认为对算法进行一些小的调整是可行的

  • 正如Grodrigues所说,首先在O(n)时间内找到中值。当我们在做的时候,记录最大和最小的数字
  • 接下来,创建一个数组K,K个项目长。此数组将包含项目与中间带的距离。(注意
  • 将前k项从A复制到k
  • 对于每个项目A[i],比较A[i]从中间值到K的每个项目的距离。如果A[i]在K中,距离中位数最近的项目比距离中位数最远的项目更接近中位数,请替换该项目。作为优化,我们还可以跟踪距离中位数最近和最远的项目,以便与K进行更快的比较,或者我们可以对K进行排序,但无需在O(n)时间内进行优化
  • <> Pseudocode,C++ +ISH:

    /* n = length of array * array = A, given in the problem * result is a pre-allocated array where the result will be placed * k is the length of result * * returns * 0 for success * -1 for invalid input * 1 for other errors * * Implementation note: optimizations are skipped. */ #define SUCCESS 0 #define INVALID_INPUT -1 #define ERROR 1 void find_k_closest(int n, int[] array, int k, int[] result) { // if we're looking for more results than possible, // it's impossible to give a valid result. if( k > n ) return INVALID_INPUT; // populate result with the first k elements of array. for( int i=0; i<k; i++ ) { result[i] = array[i]; } // if we're looking for n items of an n length array, // we don't need to do any comparisons // Up to this point, function is O(k). Worst case, k==n, // and we're O(n) if( k==n ) return 0; // Assume an O(n) median function // Note that we don't bother finding the median if there's an // error or if the output is the input. int median = median(array); // Convert the result array to be distance, not // actual numbers for( int i=0; i<k; i++) { result[i] = result[i]-median; // if array[i]=1, median=3, array[i] will be set to 2. // 4 3 -1. } // Up to this point, function is O(2k+n) = O(n) // find the closest items. // Outer loop is O(n * order_inner_loop) // Inner loop is O(k) // Thus outer loop is O(2k*n) = O(n) // Note that we start at k, since the first k elements // of array are already in result. OUTER: for(int i=k; i<n; i++) { int distance = array[i]-median; int abs_distance = abs(distance); // find the result farthest from the median int idx = 0; #define FURTHER(a,b) ((abs(a)>abs(b)) ? 1 : 0; INNER: for( int i=1; i<k; i++ ) { idx = (FURTHER(result[i],result[i-1])) ? i:i-1; } // If array[i] is closer to the median than the farthest element of // result, replace the farthest element of result with array[i] if( abs_distance < result[idx] ){ result[idx] = distance; } } } // Up to this point, function is O(2n) // convert result from distance to values for( int i=0; i<k; i++) { result[i] = median - result[i]; // if array[i]=2 , median=3, array[i] will be set to 1. // -1 3 4. } } /*n=数组的长度 *数组=A,在问题中给出 *结果是一个预先分配的数组,结果将放置在该数组中 *k是结果的长度 * *返回 *0代表成功 *-1表示输入无效 *1对于其他错误 * *实现说明:跳过优化。 */ #定义成功0 #定义无效的\u输入-1 #定义错误1 void find_k_最近(int n,int[]数组,int k,int[]结果) { //如果我们在寻找比可能更多的结果, //不可能给出一个有效的结果。 如果(k>n)返回无效的_输入; //用数组的前k个元素填充结果。
    对于(int i=0;iIMO),您必须对列表进行排序,排序值始终大于O(n)。您的问题相当于能够在O(n)时间内找到任意百分位。仅在O(n)时间内找到中位数(即解决k=1的问题)是可能的,但不是微不足道的。该算法可能会被扩展以找到百分位数。你为什么需要它?这是家庭作业吗?Dup:?你如何找到O(n)中的中值?寻找霍尔的快速选择算法:我尝试了4-5次向上投票,但也阻止了我向上投票。