题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
方法一、
class Solution {
public:
int NumberOf1(int n) {
int count = 0;
int flag = 1;
while (flag != 0)
{
if ((n & flag) != 0) //将1(之后右移)和n进行与运算,判断n的每一位是否是1
{
count++;
}
flag = flag << 1;//将1每次右移一位
}
return count;
}
};
方法二、
有一个数1100,把这个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0.那么一个整数的二进制有多少个1,就可以进行多少次这样的操作。1100&1011=1000
class Solution {
public:
int NumberOf1(int n) {
int count = 0;
while(n!= 0)
{
count++;
n = n & (n - 1);
}
return count;
}
};
方法三、
首先判断n是不是负数,当n为负数的时候,直接用后面的
while
循环会导致死循环,因为负数
向左移位的话最高位补1
!为了使最高位的符号位
1
变成
0
,使用
n & 0x7FFFFFFF
,把负数转化成正数,最高位由
1
变成
0
,因为少了
一个1
,所以count加
1
。变成正数后就可以执行
while
循环。
class Solution {
public:
int NumberOf1(int n) {
int count = 0;
if(n < 0){
n = n & 0x7FFFFFFF;
++count;
}
while(n != 0){
count += n & 1;
n = n >> 1;
}
return count;
}
};
方法四、
标准库提供了bitset类使得处理位集合更容易一些
class Solution {
public:
int NumberOf1(int n) {
bitset<32> bit(n);
return bit.count();
//合并成一句话:return bitset<32>(n).count();
}
};
按位与运算符(&)
参加运算的两个数据,按二进制位进行“与”运算。
运算规则:0&0=0; 0&1=0; 1&0=0; 1&1=1;
即:两位同时为“1”,结果才为“1”,否则为0
注意:负数按补码形式参加按位与运算。
取反运算符(~)
参加运算的一个数据,按二进制位进行“取反”运算。
运算规则:~1=0; ~0=1;
即:对一个二进制数按位取反,即0变1,1变0。
“~”运算符的优先级比算术运算符、关系运算符、逻辑运算符和其他运算符都高。低于 ++,--
左移运算符(<<)
将一个数的各二进制位全部左移若干位(左边的二进制位丢弃,右边补0)。
例:a = a<< 2将a的二进制位左移2位,右补0,
左移1位后a = a *2;
若左移时舍弃的高位不包含1,则每左移一位,相当于该数乘以2。
右移运算符(>>)
将一个数的各二进制位全部右移若干位,正数左补0,负数左补1,右边丢弃。
操作数每右移一位,相当于该数除以2。
例如:a = a>> 2 将a的二进制位右移2位,
无符号右移运算符(>>>)
>>>运算符把一个数的各个位向右移指定的位数。右移后左边空出的位用零来填充。移出右边的位被丢弃。
例如:int temp = -14 >>>2
变量 temp的值为 -14 (即二进制的 11111111 11111111 1111111111110010),向右移两位后二进制为 00111111 11111111 1111111111111100)。
不同长度的数据进行位运算
如果两个不同长度的数据进行位运算时,系统会将二者按右端对齐,然后进行位运算。
以“与”运算为例说明如下:我们知道在C语言中long型占4个字节,int型占2个字节,如果一个long型数据与一个int型数据进行“与”运算,右端对齐后,左边不足的位依下面三种情况补足,
(1)如果整型数据为正数,左边补16个0。
(2)如果整型数据为负数,左边补16个1。
(3)如果整形数据为无符号数,左边也补16个0。