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 (nk)×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(nlogk) 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(kn/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(nlogk)kO(k)O(logk)O(k+nlogk)O(nlogk)

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(logn)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(logn)O(k)O(logn)264log264=64kn


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

@ xavierm02 = O ( k ) . Prova: il caso peggiore per k è n . Il caso peggiore per m i n ( k , n - k ) è nO(min(k,nk))O(k)knmin(k,nk) . Sono gli stessi all'interno di un fattore costante, quindi O(min(k,n-k))=O(k). n2O(min(k,nk))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,nk))CMMknkC(nk)n=k+). Quindi . O(min(k,nk))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.