Ich habe diese Interviewfrage oft gestellt bekommen und ich hatte gehofft, einige Meinungen darüber zu bekommen, was gute Antworten sein könnten: Sie haben eine große Datei mit mehr als 10 GB und möchten herausfinden, welches Element am häufigsten vorkommt, was ein guter Weg ist um dies zu tun?
Das Wiederholen und Verfolgen einer Map ist wahrscheinlich keine gute Idee, da Sie viel Speicher verwenden und das Verfolgen von eingehenden Einträgen nicht die beste Option ist, da die Datei in der Regel bereits vorhanden ist, wenn diese Frage gestellt wird.
Andere Überlegungen, die ich angestellt hatte, waren das Aufteilen der Datei, die von mehreren Threads durchlaufen und verarbeitet werden soll, und dann das Kombinieren dieser Ergebnisse, aber das Speicherproblem für die Maps ist immer noch vorhanden.
quelle
Antworten:
Wenn Sie eine haben wirklich große Datei und viele Elemente darin, aber das häufigste Element ist sehr häufig - tritt Bruchteil der Zeit - Sie können es in linearer Zeit mit Platz finden O ( k ) Worte (die Die Konstante in der O ( ) - Notation ist sehr klein (im Grunde genommen 2, wenn Sie den Speicher für Hilfssachen wie Hashing nicht mitzählen). Darüber hinaus funktioniert dies hervorragend mit externem Speicher, da die Datei elementweise nacheinander verarbeitet wird und der Algorithmus niemals "zurückschaut". Ein Weg, dies zu tun, ist über einen klassischen Algorithmus von Misra und Gries, siehe diese Vorlesungsunterlagen>1/k O(k) O() . Das Problem ist jetzt als das Problem der schweren Schläger bekannt (die häufigsten Elemente sind die schweren Schläger).
Die Annahme, dass das häufigste Element Bruchteil der Zeit für k eine kleine Zahl erscheint, mag stark erscheinen, ist aber in gewisser Weise notwendig! Dh, wenn Sie sequentiellen Zugriff auf Ihre Datei haben (und wenn die Datei sehr umfangreich ist, ist der zufällige Zugriff zu teuer), verwendet jeder Algorithmus, der immer das häufigste Element in einer konstanten Anzahl von Durchläufen findet, linearen Raum in der Anzahl der Elemente . Wenn Sie also nichts von der Eingabe annehmen, können Sie eine Hash-Tabelle nicht schlagen. Die Annahme, dass das häufigste Element sehr häufig ist, ist möglicherweise der natürlichste Weg, um die negativen Ergebnisse zu umgehen.>1/k k
Hier ist eine Skizze für , dh wenn es ein einzelnes Element gibt, das mehr als die Hälfte der Zeit auftritt. Dieser Sonderfall ist als Mehrheitswahlalgorithmus bekannt und geht auf Boyer und Moore zurück. Wir behalten ein einzelnes Element und eine einzelne Zählung bei. Initialisieren Sie den Zähler auf 1 und speichern Sie das erste Element der Datei. Verarbeiten Sie dann die Datei in der folgenden Reihenfolge:k=2
Ein bisschen Nachdenken über diese Prozedur wird Sie davon überzeugen, dass, wenn ein "Majoritäts" -Element existiert, dh eines, das mehr als die Hälfte der Zeit auftritt, dieses Element das gespeicherte Element ist, nachdem die gesamte Datei verarbeitet wurde.
Für allgemeines behalten Sie k - 1 Elemente und k - 1 Zählwerte bei und initialisieren die Elemente mit den ersten k verschiedenen Elementen der Datei und den Zählwerten, bis zu der Häufigkeit, mit der jedes dieser Elemente angezeigt wird, bevor Sie das sehenk k−1 k−1 k k
quelle
Die naheliegende Antwort ist natürlich, eine Hash-Karte zu führen und einen Zähler für das Auftreten von Elementen zu speichern, während Sie sich durch die Datei bewegen, wie es Nejc bereits vorgeschlagen hat. Dies ist (in Bezug auf die zeitliche Komplexität) die optimale Lösung.
quelle
Wenn das häufigste Element deutlich häufiger als das nächste gemeinsame Element ist und die Anzahl der verschiedenen Elemente im Vergleich zur Dateigröße gering ist, können Sie mehrere Elemente zufällig auswählen und das häufigste Element in Ihrem Beispiel zurückgeben.
quelle