Suchen Sie den Median einer Liste sortierter Arrays

8

Eingabe: Eine Menge von Arrays (von Zahlen). Die Elemente in jedem Array sind in sortierter Reihenfolge, aber der Satz von Arrays ist nicht unbedingt sortiert. Die Arrays haben nicht unbedingt die gleiche Größe. Die Gesamtzahl der Elemente beträgt .A i nAi
n

Ausgabe: Das -kleinste Element aller Elemente in der Eingabe.k

Was ist der effizienteste Algorithmus für dieses Problem?

Ist es beispielsweise möglich, eine Laufzeit von ?O(+logn)

Joe
quelle
Es gibt eine sehr eng verwandte Frage zu SO mit unbefriedigenden Antworten.
Joe
Sind alle Arrays gleich lang?
vonbrand
Die Arrays haben nicht unbedingt die gleiche Größe. Ich interessiere mich jedoch auch für einen Sonderfall, bei dem die Größen geometrisch sind, das Array hat die Größe , aber ich bezweifle, dass dies in der Laufzeit hilfreich sein wird. n / 2 iAin/2i
Joe
4
Wie bekommt man ? Sie können indem Sie den "Quickselect" -Algorithmus emulieren. In jeder Phase wählen Sie einen Drehpunkt aus und berechnen in wie viele Elemente darunter liegen . Dann entfernen Sie Elemente auf der falschen Seite und wiederholen. Der Prozess endet nach Iterationen (erwartungsgemäß oder im schlimmsten Fall, wenn Sie den Pivot intelligent auswählen). O ( ( log n ) 2 ) O ( log n ) log nO(logn)O((logn)2)O(logn)logn
Yuval Filmus
2
@ Joe Ich denke, du solltest auch deinen Algorithmus beschreiben. Es wäre sehr interessant und könnte einen Ausgangspunkt für bessere Algorithmen bieten, wenn es korrekt ist. Wenn dies nicht der Fall ist, können möglicherweise Fehler gefunden werden.
Paresh

Antworten:

5

Sie können dies in Zeit und zusätzlichem Speicherplatz wie folgt tun :O ( l )O(l+k log l)O(l)

  1. Erstellen Sie einen binären Heap mit einem Eintrag für jedes der Arrays. Der Schlüssel für Eintrag ist das kleinste Element in Array . Dies dauert Zeit.A i O ( l )iAiO(l)
  2. Wählen Sie den kleinsten Eintrag aus dem Heap aus und entfernen Sie ihn (wobei Sie sich ) Zeit nehmen). Fügen Sie diesen Eintrag wieder zum Heap hinzu, indem Sie den nächstkleineren Eintrag im entsprechenden Array als Schlüssel verwenden (erneut time).O ( log  l )O(log lO(log l)
  3. Führen Sie den vorherigen Schritt mal aus. Das letzte Element, das Sie vom Heap entfernen, ist Ihre Antwort.k

Wenn Sie den binären Heap durch einen Fibonacci-Heap ersetzen, werden Sie wahrscheinlich auf die amortisierte -Zeit reduziert , aber in der Praxis ist er langsamer als der binäre Heap, es sei denn, ist RIESIG.lO(l+k)l

Ich vermute, dass die Fibonacci-Heap-Bindung optimal ist, weil Sie intuitiv mindestens Elemente untersuchen müssen, um das -kleinste zu finden, und Sie müssen mindestens ein Element von jedem der Arrays, da Sie nicht wissen, wie sie sortiert sind, was sofort eine Untergrenze von ergibt .k l Ω ( max ( k , l ) ) = Ω ( k + l )kklΩ(max(k,l))=Ω(k+l)

Matt Lewis
quelle
3
Sie müssen nicht mindestens Elemente untersuchen, da die Arrays sortiert sind. Siehe die Lösung in meinem Kommentar, der ergibt . kO((logn)2)
Yuval Filmus
1
Sie können die Worst-Case-Laufzeit im RAM-Modell verbessern, da Sie möglicherweise Ihre Prioritätswarteschlange für Elemente in implementieren . In diesem Modell können Sie sowohl für Einfüge- als auch für Löschoperationen und Zeit für die findMin-Operation erzielen. no(logn)O(loglogn)O(1)
Massimo Cafaro
1
Sind Sie sicher, dass der Fibonnaci-Heap die richtige Operation unterstützt? Ich denke, Sie denken an Abnahme- Schlüssel in einem Min-Haufen.
Joe
Dies ist im Grunde das Gleiche wie vonbrands Antwort, mit der zusätzlichen Beobachtung, dass Sie nach dem k-ten keine Elemente mehr zusammenführen müssen.
Joe
Ich glaube, mit dem Fibonacci-Haufen können Sie einen Schlüssel in -Zeit verringern oder erhöhen . Ja, dies ist im Grunde die gleiche Antwort, aber wenn Sie feststellen, dass Sie nur Elemente zusammenführen müssen, wird Ihre Laufzeit auf faire Weise verkürzt. O(1)k
Matt Lewis
5

Hier ist ein randomisierter -Algorithmus. Es kann wahrscheinlich mit demselben Trick derandomisiert werden, mit dem die übliche Schnellauswahl derandomisiert wird.O(log2n)

Wir emulieren den klassischen Schnellauswahlalgorithmus. In jeder Phase wählen Sie einen Drehpunkt aus und berechnen mithilfe der binären Suche in jeder Liste, wie viele Elemente sich darunter in . Dann entfernen Sie Elemente auf der falschen Seite und wiederholen. Der Prozess endet erwartungsgemäß nach Iterationen.O(logn)logn

Yuval Filmus
quelle
1

Dies scheint durch das Papier Allgemeine Auswahl und Rangfolge (vorläufige Version) von Frederickson und Johnson in STOC '80 gelöst zu werden.

Sie geben die oberen und unteren Grenzen von: was sich für die meisten Arraygrößenverteilungen als herausstellt .Θ(+i=1log|Ai|)logn

Der eigentliche Algorithmus zum Erreichen der Obergrenze ist offenbar in einem früheren Artikel angegeben: Optimale Algorithmen zum Erzeugen von Quantilinformationen in X + Y und Matrizen mit sortierten Spalten , Proc. 13. Jahreskonferenz über Informationswissenschaft und -systeme, Johns Hopkins University (1979) 47-52.

Joe
quelle
0

Eine -way-Zusammenführung benötigt Zeit (verwenden Sie eine effiziente Methode, um eine Prioritätswarteschlange der Kopfelemente in jeder Liste darzustellen), und wählen Sie dann das te Element in konstanter Zeit aus. Ich denke, das wird in Knuths "Sortieren und Suchen" zum Sortieren besprochen. Das kleinste (oder größte erfordert eindeutig , für ein unsortiertes Array ist es IIRC.Θ ( n log l ) k Θ ( l ) O ( n )Θ(nlog)kΘ()O(n)

Bitte beschreiben Sie Ihren Algorithmus.

vonbrand
quelle
1
Dies ist viel langsamer als ich interessiert bin. Sie können den Median in Zeit finden, indem Sie nur die Listen verketten und den linearen Zeitauswahlalgorithmus verwenden. O(n)
Joe