Angenommen, wir lesen eine Folge von Zahlen nacheinander. So finden Sie das k -kleinste Element nur mit dem O ( k ) -Zellenspeicher und in linearer Zeit ( O ( n ) ). Ich denke, wir sollten die ersten k Terme der Sequenz speichern und, wenn wir den k + 1 -ten Term erhalten, einen Term löschen, von dem wir sicher sind, dass er nicht das k -kleinste Element sein kann, und dann den k + 1 -ten Term speichern . Wir sollten also einen Indikator haben, der diesen unbrauchbaren Begriff in jedem Schritt anzeigt, und dieser Indikator sollte in jedem Schritt schnell aktualisiert werden. Ich begann mit "max";; Es kann jedoch nicht schnell aktualisiert werden. Bedeutet, wenn wir max berücksichtigen, dann verpassen wir beim ersten Löschen das Maximum und sollten in und seiner Ursache ( n - k ) × O ( k ) Zeit nach max suchen , damit es nicht linear ist. Vielleicht sollten wir die ersten k Terme der Sequenz intelligenter speichern .
Wie löse ich dieses Problem?
quelle
Antworten:
Erstellen Sie einen Puffer der Größe . Lesen Sie 2 k Elemente aus dem Array ein. Verwenden Sie einen linearen Zeitauswahlalgorithmus, um den Puffer so zu partitionieren, dass die k kleinsten Elemente an erster Stelle stehen. Dies dauert O ( k ) Zeit. Lesen Sie nun weitere k Elemente aus Ihrem Array in den Puffer ein, ersetzen Sie die k größten Elemente im Puffer, partitionieren Sie den Puffer wie zuvor und wiederholen Sie den Vorgang.2k 2k k O(k) k k
Dies dauert Zeit und O ( k ) Raum.O(k∗n/k)=O(n) O(k)
quelle
min
Sie können dies im -Speicher und in der O ( n log k ) -Zeit tun, indem Sie aus den ersten k Elementen in der O ( k ) -Zeit einen Max-Heap mit fester Größe bilden , dann über den Rest des Arrays iterieren und einen neuen verschieben Element und dann Popping für O ( log k ) für jedes Element, was die Gesamtzeit O ( k + n log k ) = O ( n log k ) ergibt .O(k) O(nlogk) k O(k) O(logk) O(k+nlogk) O(nlogk)
Sie können dies im -Hilfsspeicher und in der O ( n ) -Zeit tun, indem Sie den Median-of-Medians-Auswahlalgorithmus verwenden, bei k auswählen und die ersten k Elemente zurückgeben. Ohne Änderung der Asymptotik können Sie Introselect verwenden, um den Durchschnittsfall zu beschleunigen. Dies ist der kanonische Weg, um Ihr Problem zu lösen.O(logn) O(n) k k
Technisch gesehen sind und O ( k ) unvergleichlich. Ich behaupte jedoch, dass O ( log n ) in der Praxis besser ist, da es effektiv konstant ist, wenn man bedenkt, dass kein Computersystem mehr als 2 64 Byte Speicher hat, log 2 64 = 64 . In der Zwischenzeit kann k so groß werden wie n .O(logn) O(k) O(logn) 264 log264=64 k n
quelle