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?
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.
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 .
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).
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;
}
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);
}
countBits(x){
y=0;
while(x){
y += x & 1 ;
x = x >> 1 ;
}
}
c'est tout?
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.
Ci-dessous fonctionnera aussi bien.
nofone(int x) {
a=0;
while(x!=0) {
x>>=1;
if(x & 1)
a++;
}
return a;
}
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
Vous trouverez ci-dessous deux exemples simples (en C++) parmi lesquels vous pouvez le faire.
Nous pouvons simplement compter les bits définis (1) en utilisant __builtin_popcount ().
int numOfOnes(int x) {
return __builtin_popcount(x);
}
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!
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;
}
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;
}
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)
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
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.
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;
}
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 :)
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
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é.
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.
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