2010-11-04 6 views
5

sen n maddelerin bir dizi A olduğunu varsayalım ve Örneğin A'nın ortanca en yakın bir k öğeleri bulmak istiyoruz, A 9 değerlerini içeriyorsa {7, 14, 10, 12, 2, 11, 29, 3, 4} ve k = 5, orta 10 olup, bu beş değerleri olduğundan daha sonra cevap değerleri {7, 14, 10, 12, 11}, olurdu 10 değerine en yakın. O (n) sürede bu sorunu çözmek için bir algoritma verin.seçim algoritması sorun

Bir seçim algoritması (derin seçim) bu sorun için uygun algoritma olduğunu biliyorum, ama o O (n) yerine O (n * logn) zaman aday olacağını düşünüyorum. Herhangi bir yardım büyük takdir :) Önce (Hoare'nın Quickselect algoritması kullanarak örneğin) O(n) yapılabilir medyan, bulmanız gerekir

+0

IMO sen listeyi sıralamak zorunda kalacak ve bu her zaman O (n) 'den büyük olacaktır. – leppie

+0

Sorununuz, O (n) saatinde rasgele persentil bulabilmekle eşdeğerdir. ** sadece ** O (n) zamanındaki medyanı bulmak (yani probleminizi k = 1 için çözmek) mümkündür ancak önemsiz değildir. Algoritma muhtemelen yüzdelerini bulmak için genişletilebilir. Niçin buna ihtiyacın var? Ödev mi? –

+1

Dup: http://stackoverflow.com/questions/1557678/how-to-find-k-nearest-neighbors-to-the-median-of-n-distinct-numbers-in-on-time? – dfens

cevap

5

.

Sonra ortanca onların mutlak mesafeye göre dizideki elemanları (en küçük mesafeleri önce) sıralayan bir sıralama algoritması uygulaması gerekecektir.

Dizinin tamamını bu şekilde sıralayacak olursanız, kullanılan algoritmaya bağlı olarak, bu genellikle O(n * log n)'dan O(n^2)'a kadar bir yer alır. Ancak, yalnızca ilk k değerlerine gereksiniminiz olduğundan, karmaşıklık O(k * log n) - O(k * n) olarak düşürülür. k yana

bir sabittir ve, en kötü durum senaryosunda, genel karmaşıklığı olacak dizi büyüklüğüne bağlı değildir: O(n) genel O(n) olan (sıralama) + O(k * n), (medyan bulmak için).

+0

O (n) 'de medyanı nasıl bulabilirsiniz? –

+0

Hoare'nin hızlı seçim algoritmasını arayın: http://en.m.wikipedia.org/wiki/Selection_algorithm ve http://en.m.wikipedia.org/wiki/Quickselect – Grodriguez

+0

Üzgünüm, bunu bilmiyordum. açıkladığın için teşekkürler. –

0

Sanırım bunu QuickSort'ta bir varyant kullanarak yapabilirsiniz.

Sen n öğeler kümesi S ile başlar ve "orta" k kalemleri için arıyoruz. Bunu S bölümlerini n - k/2 ("alt" öğeler), k ("orta" öğeler) ve n - k/2 ("üst" öğeler) olmak üzere üç bölüm halinde düşünebilirsiniz.

Bu bize bir strateji verir: İlk alt n kaldırmak - S bırakarak S'den/2 öğe k'. Ardından S '' den üst n - k/2 maddelerini kaldırın, S '' yi terk edin, bu da S '' dir, ki bu da S'nin orta k parçalarıdır.

Bu seti "yarım hızlı bağlantı noktası" kullanarak kolayca bölebilirsiniz: bir mil , seti L ve U'ya (alt ve üst elemanlar pivot) ayırın, daha sonra bölümdeki atılacak öğelerin ya L ve bazı U ya da tam tersi olması gerektiğini bilirsiniz: buna göre tekrarla.

[bu tanımlarsanız ne istediğinizi tam olmayabilir, ayrıca düşünmek başka bir şekilde "ortanca en yakın", ama bu bir başlangıç.]

0

Varsayım: Biz A k değerlerine önem medyanın en yakınları. Eğer bir A = {1,2,2,2,2,2,2,2,2,2,2,2,3} ve k = 3 olsaydı, cevap {2,2,2}. Benzer şekilde A = {0,1,2,3,3,4,5,6}, k = 3 ise, {2,3,3} ve {3,3,4} cevapları eşit olarak geçerlidir. Dahası, bu değerlerin geldiği endekslerle ilgilenmiyoruz, ancak algoritmanın işe yarayacağı küçük ufak tefek şeyler hayal ediyorum.

  1. olarak Grodrigues durumları, ilk O (n) zamanda orta değerlerini bulmak. Biz varken, en büyük ve en küçük sayıyı takip edin
  2. Sonraki, K, k öğeleri uzun bir dizi oluşturun. Bu dizi, bir maddenin medyandan uzaklığını içerecektir.(A [i] ise her öğe için K.
  3. içine bir ilk k ürün A [i] [i] ortanca K. her öğeye A'nın mesafeyi karşılaştırmak
  4. kopyala unutmayın medyandan K'ye en uzak olandan daha yakın olana, o maddeyi değiştirir.Bir optimizasyon olarak, K'nın en yakın ve en uzak öğelerini de ortanca izleyebiliriz, bu yüzden K ile daha hızlı bir karşılaştırma yapabiliriz veya K dizisini tutabiliriz ama ne optimizasyon O (n) zaman içinde çalıştırmak için gerekli olan

Pseudocode C++ imsi.

 
/* 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. 
    } 
}