Предположение: мы заботимся о значениях k в A, которые являются ближайшими к медиане. Если бы у нас было 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} одинаково действительны. Кроме того, нас не интересуют индексы, из которых получены эти значения, хотя я предполагаю, что некоторые небольшие изменения в алгоритме сработают.
- Как утверждает Гродригес, сначала найдите медиану за O (n) времени. Пока мы это делаем, следите за самым большим и самым маленьким числом
- Далее создайте массив K, длиной k элементов. Этот массив будет содержать расстояние, на которое элемент находится от медианы. (обратите внимание, что
- Скопируйте первые k элементов из A в K.
- Для каждого элемента A [i] сравните расстояние A [i] от медианы до каждого элемента K. Если A [i] ближе к медиане, чем самый дальний элемент из медианы в K, замените это вещь. В качестве оптимизации мы могли бы также отслеживать самые близкие и самые отдаленные элементы K по медиане, поэтому мы имеем более быстрое сравнение с K, или мы можем сохранить сортировку K, но ни одна оптимизация не требуется для работы за O (n) времени.
Псевдокод, 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.
}
}