web-dev-qa-db-fra.com

Compter le nombre de 1 dans la représentation binaire

Méthode efficace pour compter le nombre de 1 dans la représentation binaire d’un nombre dans O(1) si vous avez assez de mémoire pour jouer. C'est une question d'entrevue que j'ai trouvée sur un forum en ligne, mais qui n'avait pas de réponse. Quelqu'un peut-il suggérer quelque chose, je ne peux pas penser à un moyen de le faire dans O(1) temps?

67
TimeToCodeTheRoad

C'est le poids de Hamming problème, a.k.a. Le lien mentionne des implémentations efficaces. Citant:

Avec une mémoire illimitée, nous pourrions simplement créer une grande table de recherche du poids de Hamming de chaque entier de 64 bits.

52
Óscar López

J'ai une solution qui compte les bits en O(Number of 1's) time:

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

Dans le pire des cas (lorsque le nombre est 2 ^ n - 1, tous les 1 sont en binaire), il vérifie chaque bit.

Edit: Je viens de trouver un très joli algorithme de mémoire à temps constant et constant pour le nombre de bits. La voici écrite en C:

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

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

Vous pouvez trouver la preuve de son exactitude ici .

41
0605002

Veuillez noter le fait que: n & (n-1) élimine toujours le moins significatif 1. 

Nous pouvons donc écrire le code pour calculer le nombre de 1 comme suit:

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

La complexité du programme serait la suivante: nombre de 1 dans n (qui est constamment <32).

17
Sriram Mahavadi

J'ai vu la solution suivante d'un autre site web:

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 ;
     }
   }

c'est tout?

6
user40521

Ce sera la réponse la plus courte de ma vie SO:table de correspondance.

Apparemment, je dois expliquer un peu: "si vous avez assez de mémoire pour jouer", cela signifie que nous avons toute la mémoire dont nous avons besoin (possibilité technique peu importe). Désormais, vous n'avez pas besoin de stocker une table de recherche pour plus d'un octet ou deux. Bien que ce soit techniquement Ω (log (n)) plutôt que O (1), il suffit de lire un nombre dont vous avez besoin pour obtenir Ω (log (n)). Si cela pose un problème, la réponse est:impossible- qui est encore plus court.

Laquelle des deux réponses qu’ils attendent de vous lors d’une interview, personne ne le sait.

Il existe une autre astuce: alors que les ingénieurs peuvent prendre un nombre et parler de Ω (log (n)), où n est le nombre, les informaticiens diront qu’en réalité, nous devons mesurer le temps d’exécution en fonction de longueur d’une entrée, donc ce que les ingénieurs appellent Ω (log (n)) est en réalité Ω (k), où k est le nombre d’octets. Cependant, comme je l’ai déjà dit, il suffit de lire Ω (k) pour lire un nombre. Il n’ya donc aucun moyen de faire mieux que cela.

3
alf

Ci-dessous fonctionnera aussi bien.

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

La meilleure façon de le faire en javascript est

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

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

où binaryValue est la chaîne binaire, par exemple: 1100

1
Vishwadeep Kapoor

Vous trouverez ci-dessous deux exemples simples (en C++) parmi lesquels vous pouvez le faire. 

  1. Nous pouvons simplement compter les bits définis (1) en utilisant __builtin_popcount ().

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

  2. Parcourez tous les bits d'un entier et vérifiez si un bit est défini et s'il est ensuite incrémenté de la variable count.

    int hammingDistance(int x) { int count = 0 for(int i = 0; i < 32; i++) if(x & (1 << i)) count++; return count; }

J'espère que cela t'aides! 

1
Gaurav Sharma

La fonction prend une int et retourne le nombre d'ions dans la représentation binaire

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

Voici une solution C utilisant des opérateurs de bits:

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

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

Voici une solution Java utilisant des puissances de 2:

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 implémentation 

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

Deux manières::

/* 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

Utilisation ::

    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

Je suis venu ici avec la conviction que je connais une belle solution à ce problème. Code en C:

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

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

        return count;
    }

Mais après avoir pris un peu de recherche sur ce sujet (lire d'autres réponses :)), j'ai trouvé 5 algorithmes plus efficaces. L'amour SO!

Il existe même une instruction de la CPU spécialement conçue pour cette tâche: popcnt. (Mentionné dans cette réponse )

Vous pouvez trouver ici une description et une analyse comparative de nombreux algorithmes.

0
naXa

La méthode ci-dessous peut également compter le nombre de 1 en nombres négatifs.

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

Cependant, un nombre tel que -1 est représenté en binaire par 111111111111111111111111111111111111 et nécessitera donc beaucoup de changement de vitesse. Si vous ne voulez pas faire autant de changements pour les petits nombres négatifs, une autre solution pourrait être la suivante:

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

Je devais jouer au Ruby et je me suis retrouvé avec

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

Utilisation: 

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

Évidemment pas efficace mais fait le tour :)

0
hoang

En utilisant les opérations de chaîne de JS, on peut faire comme suit;

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

ou

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

En fait, je l'ai fait à l'aide d'un tour de passe-passe: une seule table de recherche avec 16 entrées suffira et il vous suffira de casser le représentant binaire en nœuds (tuples 4 bits). La complexité est en fait O(1) et j’ai écrit un modèle C++ spécialisé sur la taille de l’entier que vous vouliez (en # bits)… en fait une expression constante au lieu d’indéterminée.

si vous pouvez utiliser le fait que (i & -i) vous retournera le bit un bit LS et qu’il bouclera tout simplement, en supprimant le bit-bit à chaque fois, jusqu’à ce que le nombre entier soit égal à zéro - mais c’est un vieux tour de parité.

0
kai26873

Dans O (1), il n’ya qu’une façon de réaliser cette tâche ... c’est de «tricher» et d’utiliser un périphérique physique (avec une programmation linéaire ou même parallèle, je pense que la limite est O(log(k)) où k représente le nombre d'octets du nombre).

Cependant, vous pouvez très facilement imaginer un dispositif physique qui connecte chaque bit à une ligne de sortie avec une tension de 0/1. Ensuite, vous pouvez simplement lire électroniquement la tension totale sur une ligne de «somme» dans O (1). Il serait assez facile de rendre cette idée de base plus élégante avec certains éléments de circuit de base pour produire la sortie sous la forme de votre choix (par exemple une sortie codée binaire), mais l'idée de base est la même et le circuit électronique produirait la sortie correcte. Etat à temps fixe.

J'imagine qu'il existe également des possibilités informatiques quantiques possibles, mais si on nous permettait de le faire, je penserais qu'un simple circuit électronique est la solution la plus simple.

0
Tim Gee

En python ou toute autre chaîne convertie en chaîne bin, divisez-la avec "0" pour supprimer les 0, puis combinez-la et obtenez la longueur.

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