Effiziente Methode zum Zählen der Anzahl von Einsen in der binären Darstellung einer Zahl in O (1), wenn Sie über genügend Speicher zum Spielen verfügen. Dies ist eine Interviewfrage, die ich in einem Online-Forum gefunden habe, die aber keine Antwort hatte. Kann jemand etwas vorschlagen, ich kann mir keinen Weg vorstellen, es in O (1) Zeit zu tun?
75
Antworten:
Das ist das Hamming-Gewichtsproblem , auch bekannt als Bevölkerungszahl. Der Link erwähnt effiziente Implementierungen. Zitat:
quelle
Ich habe eine Lösung, die die Bits in der
O(Number of 1's)
Zeit zählt:Im schlimmsten Fall (wenn die Zahl 2 ^ n - 1 ist, sind alle 1 binär) wird jedes Bit überprüft.
Bearbeiten: Habe gerade einen sehr schönen Algorithmus mit konstanter Zeit und konstantem Speicher für Bitcount gefunden. Hier ist es, geschrieben in C:
Den Beweis für die Richtigkeit finden Sie hier .
quelle
unsigned int
).Bitte beachten Sie, dass: n & (n-1) immer die niedrigstwertige 1 eliminiert.
Daher können wir den Code zur Berechnung der Anzahl der Einsen wie folgt schreiben:
Die Komplexität des Programms wäre: Anzahl der Einsen in n (was konstant <32 ist).
quelle
Ich habe die folgende Lösung von einer anderen Website gesehen:
quelle
quelle
if (orig & 1)
count++;
orig >>= 1;
ein bisschen effizienter?count += orig & 1;
orig >>= 1;
das ist es?
quelle
Das wird die kürzeste Antwort in meinem SO-Leben sein: Nachschlagetabelle.
Anscheinend muss ich ein wenig erklären: "Wenn Sie genug Speicher zum Spielen haben" bedeutet, dass wir über den gesamten Speicher verfügen, den wir benötigen (ungeachtet der technischen Möglichkeit). Jetzt müssen Sie die Nachschlagetabelle nicht länger als ein oder zwei Bytes speichern. Während es technisch gesehen eher Ω (log (n)) als O (1) ist, ist das Lesen einer benötigten Zahl Ω (log (n)). Wenn dies also ein Problem ist, ist die Antwort unmöglich - was ist noch kürzer.
Welche von zwei Antworten sie bei einem Interview von Ihnen erwarten, weiß niemand.
Es gibt noch einen weiteren Trick: Während Ingenieure eine Zahl nehmen und über Ω (log (n)) sprechen können, wobei n die Zahl ist, werden Informatiker sagen, dass wir die Laufzeit tatsächlich als Funktion der Länge einer Eingabe messen müssen Das, was Ingenieure Ω (log (n)) nennen, ist tatsächlich Ω (k), wobei k die Anzahl der Bytes ist. Wie ich bereits sagte, ist das Lesen einer Zahl Ω (k). Wir können es also auf keinen Fall besser machen.
quelle
Unten wird auch funktionieren.
quelle
Das Folgende ist eine C-Lösung mit Bitoperatoren:
Das Folgende ist eine Java-Lösung mit Potenzen von 2:
quelle
Im Folgenden finden Sie zwei einfache Beispiele (in C ++) unter vielen, anhand derer Sie dies tun können.
Wir können einfach gesetzte Bits (Einsen) mit __builtin_popcount () zählen.
int numOfOnes(int x) { return __builtin_popcount(x); }
Durchlaufen Sie alle Bits in einer Ganzzahl, prüfen Sie, ob ein Bit gesetzt ist, und erhöhen Sie dann die Zählvariable.
int hammingDistance(int x) { int count = 0 for(int i = 0; i < 32; i++) if(x & (1 << i)) count++; return count; }
Hoffe das hilft!
quelle
Die Funktion nimmt ein
int
und gibt die Anzahl der Einen in binärer Darstellung zurückquelle
Der beste Weg in Javascript ist dies
Dabei ist binaryValue der binäre String, z. B.: 1100
quelle
Es gibt nur einen Weg, wie ich mir vorstellen kann, diese Aufgabe in O (1) zu erfüllen ... nämlich ein physisches Gerät zu "betrügen" und zu verwenden (bei linearer oder sogar paralleler Programmierung denke ich, dass die Grenze O ist (log (k)). wobei k die Anzahl der Bytes der Anzahl darstellt).
Sie können sich jedoch sehr leicht ein physisches Gerät vorstellen, das jedes Bit und eine Ausgangsleitung mit einer Spannung von 0/1 verbindet. Dann können Sie einfach die Gesamtspannung auf einer Summationsleitung in O (1) elektronisch ablesen. Es wäre ziemlich einfach, diese Grundidee mit einigen grundlegenden Schaltungselementen eleganter zu gestalten, um die Ausgabe in einer beliebigen Form zu erzeugen (z. B. eine binär codierte Ausgabe), aber die wesentliche Idee ist dieselbe und die elektronische Schaltung würde die richtige Ausgabe erzeugen Zustand in fester Zeit.
Ich stelle mir vor, dass es auch Möglichkeiten für Quantencomputer gibt, aber wenn wir das dürfen, würde ich denken, dass eine einfache elektronische Schaltung die einfachere Lösung ist.
quelle
Ich habe dies tatsächlich mit ein wenig Fingerspitzengefühl getan: Eine einzelne Nachschlagetabelle mit 16 Einträgen wird ausreichen, und alles, was Sie tun müssen, ist, die binäre Wiederholung in Halbbytes (4-Bit-Tupel) zu zerlegen. Die Komplexität ist in der Tat O (1) und ich habe eine C ++ - Vorlage geschrieben, die auf die Größe der gewünschten Ganzzahl (in # Bits) spezialisiert war. Dies macht sie zu einem konstanten Ausdruck anstatt zu einem unbestimmten.
fwiw können Sie die Tatsache nutzen, dass (i & -i) Ihnen das LS-Ein-Bit zurückgibt und einfach eine Schleife abgibt, wobei jedes Mal das lsbit entfernt wird, bis die Ganzzahl Null ist - aber das ist ein alter Paritätstrick.
quelle
Ich kam hierher mit dem großen Glauben, dass ich eine schöne Lösung für dieses Problem kenne. Code in C:
Aber nachdem ich ein wenig zu diesem Thema recherchiert habe (andere Antworten lesen :)), habe ich 5 effizientere Algorithmen gefunden. Liebe so!
Es gibt sogar einen CPU-Befehl, der speziell für diese Aufgabe entwickelt wurde :
popcnt
. (in dieser Antwort erwähnt )Beschreibung und Benchmarking vieler Algorithmen finden Sie hier .
quelle
Die folgende Methode kann auch die Anzahl der Einsen in negativen Zahlen zählen.
Eine Zahl wie -1 wird jedoch binär als 111111111111111111111111111111 dargestellt und erfordert daher viele Verschiebungen. Wenn Sie nicht so viele Schichten für kleine negative Zahlen machen möchten, könnte ein anderer Weg wie folgt sein:
quelle
In Python oder einem anderen Konvertierungs-Bin-String teilen Sie ihn dann mit '0', um Nullen zu entfernen. Kombinieren Sie ihn dann und ermitteln Sie die Länge.
quelle
bin(122011).count("1")
?Durch Verwendung von String-Operationen von JS kann man wie folgt vorgehen:
oder
quelle
Ich musste dies in Rubin spielen und endete mit
Verwendung :
l[2**32-1] # returns 32
Offensichtlich nicht effizient, macht aber den Trick :)
quelle
Ruby-Implementierung
quelle
Zwei Wege::
Verwendung::
quelle