it-swarm.com.de

Anzahl der Einsen in binärer Darstellung zählen

Effiziente Möglichkeit, die Anzahl der 1s in der binären Darstellung einer Zahl in O(1) zu zählen, wenn Sie über genügend Speicher zum Spielen verfügen. Dies ist eine Interviewfrage, die ich in einem Online-Forum gefunden habe, aber keine Antwort hatte. Kann jemand etwas vorschlagen, ich kann mir nicht vorstellen, wie ich es in der Zeit O(1) tun kann?

67

Das ist das Hamming-Gewicht Problem, a.k.a. Bevölkerungszahl. Der Link erwähnt effiziente Implementierungen. Zitieren:

Mit unbegrenztem Speicher könnten wir einfach eine große Nachschlagtabelle der Hamming-Gewichtung jeder 64-Bit-Ganzzahl erstellen

52
Óscar López

Ich habe eine Lösung, die die Bits in O(Number of 1's) time zählt:

bitcount(n):
    count = 0
    while n > 0:
        count = count + 1
        n = n & (n-1)
    return count

Im schlimmsten Fall (wenn die Zahl 2 ^ n - 1 ist, sind alle 1 binär), wird jedes Bit geprüft.

Edit: Ich habe gerade einen sehr schönen konstanten Speicheralgorithmus für Bitcount gefunden. Hier ist es in C geschrieben:

int BitCount(unsigned int u)
{
     unsigned int uCount;

     uCount = u - ((u >> 1) & 033333333333) - ((u >> 2) & 011111111111);
     return ((uCount + (uCount >> 3)) & 030707070707) % 63;
}

Den Beweis für die Richtigkeit finden Sie hier .

41
0605002

Bitte beachten Sie die Tatsache, dass: n & (n-1) immer das niedrigstwertige 1 eliminiert. 

Daher können wir den Code zum Berechnen der Anzahl der Einsen wie folgt schreiben:

count=0;
while(n!=0){
  n = n&(n-1);
  count++;
}
cout<<"Number of 1's in n is: "<<count;

Die Komplexität des Programms wäre: Anzahl der Einsen in n (die konstant <32 ist).

17
Sriram Mahavadi

Ich habe die folgende Lösung von einer anderen Website gesehen:

int count_one(int x){
    x = (x & (0x55555555)) + ((x >> 1) & (0x55555555));
    x = (x & (0x33333333)) + ((x >> 2) & (0x33333333));
    x = (x & (0x0f0f0f0f)) + ((x >> 4) & (0x0f0f0f0f));
    x = (x & (0x00ff00ff)) + ((x >> 8) & (0x00ff00ff));
    x = (x & (0x0000ffff)) + ((x >> 16) & (0x0000ffff));
    return x;
}
13
user2555279
public static void main(String[] args) {

    int a = 3;
    int orig = a;
    int count = 0;
    while(a>0)
    {
        a = a >> 1 << 1;
        if(orig-a==1)
            count++;
        orig = a >> 1;
        a = orig;
    }

    System.out.println("Number of 1s are: "+count);
}
10
akus
   countBits(x){
     y=0;
     while(x){   
       y += x &  1 ;
       x  = x >> 1 ;
     }
   }

das ist es?

6
user40521

Das ist die kürzeste Antwort in meinem SO Leben:Nachschlagetabelle.

Anscheinend muss ich ein wenig erklären: "Wenn Sie genug Speicher haben, um damit zu spielen", haben wir den gesamten Speicher, den wir brauchen (technische Möglichkeit überhaupt). Jetzt müssen Sie die Lookup-Tabelle nicht länger als ein oder zwei Byte speichern. Während es technisch gesehen Ω (log (n)) und nicht O (1) ist, ist das Lesen einer Zahl, die Sie benötigen, Ω (log (n)). Wenn dies ein Problem ist, lautet die Antwort:unmöglich- was noch kürzer ist.

Welche von zwei Antworten sie von einem Interview erwarten, weiß niemand.

Es gibt noch einen weiteren Trick: Während Ingenieure eine Zahl annehmen und über Ω (log (n)) sprechen können, wobei n die Zahl ist, werden Informatiker sagen, dass wir eigentlich die Laufzeit als Funktion einer Länge) messen sollen eines Eingangs, was Ingenieure als Ω (log (n)) bezeichnen, ist tatsächlich Ω (k), wobei k die Anzahl der Bytes ist. Wie bereits gesagt, ist das Lesen einer Zahl Ω (k). Es gibt also keine Möglichkeit, das besser zu machen.

3
alf

Unten wird auch funktionieren.

nofone(int x) {
  a=0;
  while(x!=0) {
    x>>=1;
    if(x & 1)
      a++;
  }
  return a;
} 
2
Vigneswaran

Der beste Weg in Javascript ist dies

function getBinaryValue(num){
 return num.toString(2);
}

function checkOnces(binaryValue){
    return binaryValue.toString().replace(/0/g, "").length;
}

dabei ist binaryValue der binäre String, z. B .: 1100

1

Im Folgenden sind zwei einfache Beispiele (in C++) aufgeführt, mit denen Sie dies tun können. 

  1. Wir können Set Bits (1) einfach mit __builtin_popcount () zählen.

    int numOfOnes(int x) { return __builtin_popcount(x); }

  2. Durchlaufen Sie alle Bits in einer Ganzzahl, überprü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! 

1
Gaurav Sharma

Die Funktion nimmt eine int und gibt die Anzahl der Einsen in binärer Darstellung zurück

public static int findOnes(int number)
{

   if(number < 2)
    {
        if(number == 1)
        {
            count ++;
        }
        else
        {
            return 0;
        }
    }

    value = number % 2;

    if(number != 1 && value == 1)
        count ++;

    number /= 2;

    findOnes(number);

    return count;
}
1
Roshan

Das Folgende ist eine C-Lösung, die Bitoperatoren verwendet:

int numberOfOneBitsInInteger(int input) {
  int numOneBits = 0;

  int currNum = input;
  while (currNum != 0) {
    if ((currNum & 1) == 1) {
      numOneBits++;
    }
    currNum = currNum >> 1;
  }
  return numOneBits;
}

Das Folgende ist eine Java-Lösung, die Potenzen von 2 verwendet:

public static int numOnesInBinary(int n) {

  if (n < 0) return -1;

  int j = 0;
  while ( n > Math.pow(2, j)) j++;

  int result = 0;
  for (int i=j; i >=0; i--){
    if (n >= Math.pow(2, i)) {
        n = (int) (n - Math.pow(2,i));
        result++;    
    }
  }

  return result;
}
1
eb80

Ruby-Implementierung 

def find_consecutive_1(n)
  num = n.to_s(2)
  arr = num.split("")
  counter = 0
  max = 0
  arr.each do |x|
      if x.to_i==1
          counter +=1
      else
          max = counter if counter > max
          counter = 0 
      end
      max = counter if counter > max  
  end
  max
end

puts find_consecutive_1(439)
0
Jagdish N

Zwei Wege::

/* Method-1 */
int count1s(long num)
{
    int tempCount = 0;

    while(num)
    {
        tempCount += (num & 1); //inc, based on right most bit checked
        num = num >> 1;         //right shift bit by 1
    }

    return tempCount;
}

/* Method-2 */
int count1s_(int num)
{
    int tempCount = 0;

    std::string strNum = std::bitset< 16 >( num ).to_string(); // string conversion
    cout << "strNum=" << strNum << endl;
    for(int i=0; i<strNum.size(); i++)
    {
        if('1' == strNum[i])
        {
            tempCount++;
        }
    }

    return tempCount;
}

/* Method-3 (algorithmically - boost string split could be used) */
1) split the binary string over '1'.
2) count = vector (containing splits) size - 1

Verwendungszweck::

    int count = 0;

    count = count1s(0b00110011);
    cout << "count(0b00110011) = " << count << endl; //4

    count = count1s(0b01110110);
    cout << "count(0b01110110) = " << count << endl;  //5

    count = count1s(0b00000000);
    cout << "count(0b00000000) = " << count << endl;  //0

    count = count1s(0b11111111);
    cout << "count(0b11111111) = " << count << endl;  //8

    count = count1s_(0b1100);
    cout << "count(0b1100) = " << count << endl;  //2

    count = count1s_(0b11111111);
    cout << "count(0b11111111) = " << count << endl;  //8

    count = count1s_(0b0);
    cout << "count(0b0) = " << count << endl;  //0

    count = count1s_(0b1);
    cout << "count(0b1) = " << count << endl;  //1
0
parasrish

Ich kam mit dem großen Glauben hierher, dass ich eine wunderbare Lösung für dieses Problem kenne. Code in C:

    short numberOfOnes(unsigned int d) {
        short count = 0;

        for (; (d != 0); d &= (d - 1))
            ++count;

        return count;
    }

Aber nachdem ich mich ein wenig mit diesem Thema beschäftigt habe (andere Antworten lesen :)), habe ich 5 effizientere Algorithmen gefunden. Liebe so!

Es gibt sogar eine speziell für diese Aufgabe entwickelte CPU-Anweisung: popcnt. (Erwähnt in diese Antwort )

Beschreibung und Benchmarking vieler Algorithmen finden Sie hier .

0
naXa

Die untenstehende Methode kann auch die Anzahl der 1en in negativen Zahlen zählen.

private static int countBits(int number)    {
    int result = 0;
    while(number != 0)  {
        result += number & 1;
        number = number >>> 1;
    }
    return result;
}

Eine Zahl wie -1 wird jedoch binär als 11111111111111111111111111111111 dargestellt und erfordert daher viel Verschiebung. Wenn Sie nicht so viele Schichten für kleine negative Zahlen verwenden möchten, können Sie wie folgt vorgehen:

private static int countBits(int number)    {
    boolean negFlag = false;
    if(number < 0)  { 
        negFlag = true;
        number = ~number;
    }

    int result = 0;
    while(number != 0)  {
        result += number & 1;
        number = number >> 1;
    }
    return negFlag? (32-result): result;
}
0
Menezes Sousa

Ich musste in Ruby Golf spielen und endete damit

l=->x{x.to_s(2).count ?1}

Verwendungszweck : 

l[2**32-1] # returns 32

Offensichtlich nicht effizient, aber der Trick :)

0
hoang

Durch die Verwendung von Stringoperationen von JS können Sie Folgendes tun:

0b1111011.toString(2).split(/0|(?=.)/).length // returns 6

oder

0b1111011.toString(2).replace("0","").length  // returns 6
0
Redu

Ich habe dies tatsächlich mit ein bisschen Fingerspitzengefühl getan: Eine einzige Nachschlagetabelle mit 16 Einträgen reicht aus und alles, was Sie tun müssen, ist die binäre Wiederholung in Nibbles (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 von Ihnen gewünschten Ganzzahl (in # Bits) spezialisiert war ... und macht sie zu einem konstanten Ausdruck, statt unbestimmt.

sie können die Tatsache verwenden, dass (i & -i) das LS-Bit mit einem Bit zurückgibt und einfach eine Schleife durchführt, wobei jedes Mal der Lsbit-Wert abgezogen wird, bis die Ganzzahl Null ist. Dies ist jedoch ein alter Paritätstrick.

0
kai26873

Ich kann mir nur einen Weg vorstellen, um diese Aufgabe in O (1) zu erledigen ... das heißt, 'zu betrügen' und ein physisches Gerät zu verwenden (mit linearer oder sogar paralleler Programmierung denke ich, die Grenze ist O(log(k)) Dabei steht k für die Anzahl der Bytes der Anzahl).

Sie können sich jedoch sehr gut ein physikalisches Gerät vorstellen, das jedes Bit und eine Ausgangsleitung mit einer 0/1-Spannung verbindet. Dann könnten Sie einfach die Gesamtspannung auf einer Summationslinie in O (1) elektronisch ablesen. Es ist ziemlich einfach, diese Grundidee mit einigen grundlegenden Schaltungselementen eleganter zu gestalten, um den Ausgang in beliebiger Form zu erzeugen (z. B. einen binär codierten Ausgang). Die Grundidee ist jedoch dieselbe und die elektronische Schaltung würde den korrekten Ausgang erzeugen Zustand in fester Zeit.

Ich denke, es gibt auch mögliche Quantencomputermöglichkeiten, aber wenn wir das dürfen, denke ich, dass eine einfache elektronische Schaltung die einfachere Lösung ist.

0
Tim Gee

In Python oder einer anderen Konvertierung in einen Bin-String, dann mit '0' teilen, um 0 zu entfernen, dann kombinieren und die Länge ermitteln.

len(''.join(str(bin(122011)).split('0')))-1
0
ben