二进制中1的个数
算法1、(暴力枚举) O(nlongn)
思路:
对于每个数字a,a&1得到了该数字的最后一位,之后将a右移一位,直到位0,就得到了1的个数
C++ 代码
#include<iostream>
using namespace std;
int n;
int a,k;
int main(){
scanf("%d",&n);
for(int i=0;i<n;i++){
scanf("%d",&a);
k=0;
while(a){
k+=a&1;
a=a>>1;
}
printf("%d ",k);
}
return 0;
}
算法2、 (lowbit) O(nlogn)
思路:
使用lowbit操作,进行,每次lowbit操作截取一个数字最后一个1后面的所有位,每次减去lowbit得到的数字,直到数字减到0,就得到了最终1的个数;
根据计算机负数表示的特点,数字在内存中以补码形式存储,正数原码、反码、补码相同;负数表示形势是补码,就是反码+1,
如:10的补码00001010,-10的补码为反码+1,即11110110(11110101+1),二者按位与得到了00000010,就是2,10 - 2=8,8补码00001000.......一直减下去直到变成00000000
#include<iostream>
using namespace std;
int lowbit(int x){
return x&(-x);
}
int main(){
int n;
cin>>n;
while(n--){
int x;
cin>>x;
int res=0;
while(x) x-=lowbit(x),res++;
cout<<res<<' ';
}
return 0;
}
算法3、(位运算) 接近O(1)
思路:
读懂了算法2的操作就明白了,算法2的优化
#include <iostream>
using namespace std;
int cnt(int b){
int res = 0;
while (b>0) {
b = b & (b-1);
res++;
}
return res;
}
int main(){
int n, b;
cin >> n;
for (int i=0;i<n;i++) {
cin >> b;
cout << cnt(b)<<" ";
}
return 0;
}