题目描述:编写一个函数,输入是一个无符号整数(以二进制串的形式),返回其二进制表达式中数字位数为 '1' 的个数(也被称为 汉明重量))。
示例 1:输入:n = 11 (控制台输入 00000000000000000000000000001011) 输出:3
解释:输入的二进制串 00000000000000000000000000001011 中,共有三位为 '1'。
示例 2:输入:n = 128 (控制台输入 00000000000000000000000010000000) 输出:1
解释:输入的二进制串 00000000000000000000000010000000 中,共有一位为 '1'。
示例 3:输入:n = 4294967293 (控制台输入 11111111111111111111111111111101,部分语言中 n = -3) 输出:31
解释:输入的二进制串 11111111111111111111111111111101 中,共有 31 位为 '1'。
设计一个变量count 来记录 ‘1’的个数
接下来用一个循环 , 不停的用n处以2,获得的余数存入栈中,余数是‘1’则 count 加1。
class Solution {
public:
int hammingWeight(uint32_t n)
{
stack<int> st;
//将十进制无符号整数转化为二进制类型,并依次存入栈中
while(n>0)
{
st.push(n%2);
n = n/2;
}
//将二进制数从栈中依次取出,并计算‘1’的个数
int count=0;
while(!st.empty())
{
if(st.top() == 1) count++;
st.pop();
}
return count;
}
};
class Solution {
public:
int hammingWeight(uint32_t n)
{
//十进制转化为二进制,对2取余数(0、1),二进制‘1’的个数即是余数为1的个数累加
if(n == 0) return 0;
int count = 0;
while(n > 0)
{
count += n%2;
n = n/2;
}
return count;
}
};
class Solution {
public:
int hammingWeight(uint32_t n) {
int count = 0;
while(n>0)
{
if(n%2 == 1) count++;
n /= 2;
}
return count;
}
};
">>"右移 操作规则:正数前面补零,负数前面补1
"<<"左移 操作规则:无论正负数,后面补零。
逐位判断
根据 与运算 定义,设二进制数字 n ,则有:
若 n & 1 = 0,则 n 二进制 最右一位 为 0 ;
若 n & 1 = 1 ,则 n 二进制 最右一位 为 1 。
根据以上特点,考虑以下 循环判断 :
判断 n 最右一位是否为 1 ,根据结果计数。
将 n 右移一位
算法流程:
初始化数量统计变量 count = 0 。
循环逐位判断: 当 n = 0 时跳出。
若 n&1=1 ,则统计数 count 加一。
n >>= 1 : 将二进制数字 n 无符号右移一位 。
返回统计数量 count 。
class Solution {
public:
int hammingWeight(uint32_t n)
{
// 逐位判断 (判断最右边位是否为1,并右移一位,将出现的1累加起来)
if(n == 0) return 0;
int count = 0;
// 每次循环都判断最右边位是否为1,并右移一位,将出现的1累加起来。直到n=0,循环终止
while(n != 0)
{
if((n & 1) == 1) count++;
n >>= 1;
}
return count;
}
};
位运算(& flag)
基本思路:
1、将 n 与 flag=1(0001) 做 & 运算,判断 n 的最低位是否为 1,如果是1,计数器 count 加1
2、将 flag 左移一位得到 falg=2(0010),与 n 进行位与运算来判断 n 的后一位是否为1
3、重复上述步骤1→2,直到通过 flag 判断完整数 n 所有位是否为 1 为止。
class Solution {
public:
int hammingWeight(uint32_t n)
{
if(n == 0) return 0;
// 把n和1做运算,判断n的最低位是不是1,
// 接着把1左移一位得到2,再和n做运算,就能判断n的次低位是不是1
int count = 0;
unsigned int flag = 1;
while (flag)
{
if (n & flag) count++;
flag = flag << 1;
}
return count;
}
};
位运算优化
思路及解法: 观察这个运算:n & (n−1),其预算结果恰为把 n 的二进制位中的最低位的 1 变为 0
(n - 1)解析: 二进制数字 n 最右边的 1 变成 0 ,此 1 右边的 0 都变成 1 。
n&(n−1) 解析: 二进制数字 n 最右边的 1 变成 0,其余不变。
class Solution {
public:
int hammingWeight(uint32_t n)
{
// 巧用n&(n-1) (将n最右边的1置0,在n=0之前 该操作的次数即为1的个数
if(n == 0) return 0;
int count = 0;
// 每次循环都将n最右边的1置0,累加次数。直到所有1都置为0时,循环终止
while(n)
{
n = n & (n-1);
count++;
}
return count;
}
};
循环检查二进制位
思路及解法:可以直接循环检查给定整数 n 的二进制位的每一位是否为 1。
具体代码中,当检查第 i 位时,我们可以让 n 与 2^i(1 << i) 进行与运算,当且仅当 n 的第 i 位为 11 时,运算结果不为 0。
class Solution {
public:
int hammingWeight(uint32_t n)
{
if(n == 0) return 0;
int count = 0;
for(int i=0;i<32;i++)
{
if(n & (1 << i)) count++;
}
return count;
}
};
扩展话题
1、用一条语句判断一个整数是不是2的整数次方,把这个整数减去1之后再和它自己做与运算,这个整数中唯一的1就会变成0 (n > 0 && (n & (n - 1)) == 0)
2、输入两个整数 m 和 n ,计算需要改变 m 的二进制表示中的多少个位才能得到 n ?思路就2步:
求这两个数的异或
统计异或结果中1的位数
举例来说,10的二进制表示为1010,13的二进制表示为1101,需要改变3位,也就是(0111中1的个数,而0111是1010和1101异或的结果)