题目:请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如把 9 表示成二进制 1001,有 2 个 1。因此如果输入9,该函数输出2。
位运算基本概念:
五种位运算:与(&)、或(|)、异或、左移 和 右移。
ps:其中 异或(运算符 ^),1 ^ 0 = 1; 1 ^ 1 = 0; 0 ^ 0 = 0; 0 ^ 1 = 1; 即 相同为假,不同为真。
左移运算符 <<,m << n,表示将 m 向左移动 n 位,并且 最左边的 n 位被丢弃,同时最右边补上 n 个 0。比如
00001010 << 2 = 001010 00; // 最左边两位被丢弃,最右边两位 补 0;
10001010 << 3 = 01010 000;
右移运算符 >>,m >> n,表示将 m 向右移动 n 位,并且 最右边的 n 位被丢弃。但最左边的补植比较复杂,分补0 和 补1,比如
00001010 >> 2 = 00 000010; // 无符号数,最右边两位被舍弃,最左边两位 补0;
10001010 >> 3 = 111 10001; // 有符号数,最高位为1,表示是负数,因此 最右边三位被舍弃,最左边三位 补1;
常规解法:(不要用 右移运算来求解,因为若是 有符号数,会补1)
/*关键值flag,通过左移运算来求解,多少位循环多少次*/
int Numberof1(int n)
{
int count = 0;
unsigned int flag = 1;
while(flag)
{
if(n & flag) /** 0000 0001 ==> 0000 0010 ==> 0000 0100 ==> ...通过值 1 的那一位的移动(并且进行与运算)来判断 n 中 1 的个数 */
count++;
flag = flag << 1;
}
return count;
}
惊喜解法:
将一个整数减去1,再和原整数做与运算,会把该整数最右边一个1变成0。
/** n & (n - 1) 操作会将 n 最右边的一个 1 变为0,可以通过举例来理解*/
int Numberof2(int n)
{
int count = 0;
while(n)
{
count++;
n = n & (n - 1);
}
return count;
}
相关题目:
1、用一条语句判断一个整数是不是 2 的整数次方。
答:若一个数是 2 的整数次方,那其二进制表示中,有且只有一位是 1。使用 n&(n-1)
2、输入两个整数 m 和 n,计算需要改变 m 的二进制表示中的多少位才能得到 n。
答:举例,使用 异或运算,统计异或结果中 1 的个数。
/*点滴积累,我的一小步O(∩_∩)O~*/