Trovare k'th elemento più piccolo da una determinata sequenza solo con O (k) memoria O (n) tempo


11

Supponiamo di leggere una sequenza di numeri, uno per uno. Come trovare 'il più piccolo elemento solo usando la memoria della cella e in tempo lineare (nkO(k)O(n) ). Penso che dovremmo salvare i primi k termini della sequenza e quando ottieni il termine k+1 , elimina un termine che siamo sicuri che non possa essere l' elemento k più piccolo e quindi salva il termine k+1 . Quindi dovremmo avere un indicatore che mostri questo termine inutilizzabile in ogni passaggio e questo indicatore dovrebbe essere aggiornato rapidamente in ogni passaggio. Ho iniziato con "max" ; ma non può aggiornarsi rapidamente; Significa che se consideriamo maxquindi nella prima cancellazione ci manca il massimo e dovremmo cercare il massimo in O(k) e la sua causa (n−k)×O(k) che non è lineare. Forse dovremmo salvare i primi k termini della sequenza in modo più intelligente.

Come posso risolvere questo problema?


1
Sei interessato a un algoritmo online o farebbe qualche algoritmo?
— Yuval Filmus

Se k=θ(n) , puoi farlo utilizzando l'algoritmo delle statistiche degli ordini. Se k=o(n) allora puoi farlo O(k) memoria e O(nlog⁡k) tempo usando qualsiasi albero bilanciato in altezza.
— Shreesh,

Si chiama problema di selezione en.wikipedia.org/wiki/Selection_algorithm
— xavierm02

Esistono algoritmi lineari sul posto sul tempo, che puoi cercare su Google, ma sono piuttosto complicati.
— Yuval Filmus

@ xavierm02 non è identico al problema di selezione. Perché esiste un limite di memoria.
— Shahab_HK

Risposte:


16

Crea un buffer di dimensioni . Leggi in 2 k elementi dall'array. Utilizzare un algoritmo di selezione a tempo lineare per partizionare il buffer in modo che i k elementi più piccoli siano i primi; questo richiede tempo O ( k ) . Ora leggi in un altro k elementi dal tuo array nel buffer, sostituendo i k elementi più grandi nel buffer, partiziona il buffer come prima e ripeti.2k2kkO(k)kk

Questo richiede tempo e O ( k ) spazio.O(k∗n/k)=O(n)O(k)


+1, questo si adatta agli asintotici richiesti. Detto questo, non credo che questo sia più veloce di un singolo algoritmo di selezione a tempo lineare ... tranne quando è una piccola costante, quindi fornisce una prospettiva interessante. Ad esempio per k = 1 questo algoritmo produce la funzione. kk=1min
— orlp,

1
A volte, l'algoritmo di selezione del tempo lineare utilizza troppo spazio. Ad esempio, non è adatto per l'uso in un contesto di streaming o quando l'array di input è immutabile.
— jbapple

Questi sono punti validi.
— orlp

3

È possibile farlo in della memoria e O ( n log k ) tempo formando una dimensione fissa max-heap dai primi k elementi a O ( k ) tempo, poi iterando sul resto della matrice e spingendo una nuova elemento e quindi saltando fuori per O ( log k ) per ogni elemento che dà il tempo totale O ( k + n log k ) = O ( n log k ) .O(k)O(nlog⁡k)kO(k)O(log⁡k)O(k+nlog⁡k)O(nlog⁡k)

Puoi farlo nella memoria ausiliaria e nel tempo O ( n ) usando l'algoritmo di selezione mediana delle mediane, selezionando in k e restituendo i primi k elementi. Senza alcuna modifica agli asintotici, è possibile utilizzare l'introselect per accelerare il caso medio. Questo è il modo canonico per risolvere il tuo problema.O(log⁡n)O(n)kk

Ora tecnicamente e O ( k ) sono incomparabili. Tuttavia, sostengo che O ( log n ) è meglio in pratica, poiché è effettivamente costante considerando che nessun sistema di computer ha più di 2 64 byte di memoria, log 2 64 = 64 . Nel frattempo k può crescere per essere grande quanto n .O(log⁡n)O(k)O(log⁡n)264log⁡264=64kn


Si noti che è possibile migliorare la complessità dell'algoritmo basato su heap su invertendo l'ordine utilizzato dall'heap quando è interessante. O(n×log⁡min(k,n−k))
— xavierm02

@ xavierm02 = O ( k ) . Prova: il caso peggiore per k è n . Il caso peggiore per m i n ( k , n - k ) è nO(min(k,n−k))O(k)knmin(k,n−k) . Sono gli stessi all'interno di un fattore costante, quindi O(min(k,n-k))=O(k). n2O(min(k,n−k))O(k)
— orlp

@ xavierm02 Detto questo, è ancora un bel speedup :)
— orlp

è O ( k ) ma non è O ( min ( k , n - k ) ) . Supponiamo che lo sia. Poi ci sono alcuni C e alcuni M in modo che per ogni M ≤ k ≤ n , abbiamo k ≤ C ( n - k ) , che è chiaramente falso (perché possiamo prendere n = k → + ∞ ) .un,k=kO(k)O(min(k,n−k))CMM≤k≤nk≤C(n−k)n=k→+∞). Quindi . O(min(k,n−k))⊊O(k)
— xavierm02

@ xavierm02 Sono familiarità con il vostro notazione. Ad essere sinceri, in generale non ho familiarità con la notazione big- O multidimensionale , specialmente considerando che le dimensioni n , k non sono indipendenti. un,kOn,k
— orlp,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.