小知识,大挑战!本文正在参与「程序员必备小知识」创作活动。
问题
请实现一个函数,输入一个整数,输出该数二进制表示中 1 的个数。例如把9表示成二进制是1001,有2位是1。因此如果输入9,该函数输出2。
力扣链接
考察要点
对于位运算&, |, ~, ^的理解
对于二进制的理解
思路1
判断整数的最后一位是不是1, 可用用 n%1! = 0来判断, 也可以用n & 1 != 0来判断, 如果是1, 则记录下1的个数
然后将n右移1位, 也就是n >> 1, 然后继续判断最后一位是否为1, 直到最后为0
缺点:
- 不能对负整数进行1的个数的统计, 因此如果负整数的话, 将该数右移, 前面会补1, 而不是0
- 这样做还会更改原来n的值, 也不是一个好的方法
代码1
public int hammingWeight(int n) {
// 用来记录1的个数
int res = 0;
while (n != 0) {
// 如果最后一位是1, 则记录1的个数
if ((n & 1) != 0) res++;
// 将整数右移一位
n >>= 1;
}
return res;
}
思路2
基于思路1, 要对目标值进行右移. 我们可以转换思想, 对1进行左移, 然后按位&进行个数的统计
例如: 1在第0位, 进行n & 1 != 0判断, 如果该位为1, 则进行1的个数记录
然后将1 <<= 1, 进行判断; 然后1 <<= 2进行判断, 依此类推.
代码2
public int hammingWeight(int n) {
// 用来记录1的个数
int res = 0;
for (int i = 0; i < 32; i++) {
// 将1进行左移, 进行1的个数统计并记录
if ((n & (1 << i)) != 0) res++;
}
return res;
}
思路3
在一个数n不等于0的情况下
如果n & (n - 1) , 那么它的值就是将n的最右边一个1变成0
例如: 二进制数1100和它减去1的数1011进行运算, 也就是1100 & 1011 = 1000
按照这样的思路, 就会减少运算次数, 也就是一个数的二进制位中, 它有多少个1, 就进行多少次运算
代码3
public int numsOfOne3(int n) {
// 用来记录1的个数
int res = 0;
while (n != 0) {
// 只要n不等于0, 那么它的二进制位中必有一个1
res++;
// 将二进制位中最右边的1变为0
n &= (n - 1);
}
return res;
}
总结
通过本题可以加深我们对于二进制数及位运算的理解程度. 还可以学到对于设计到二进制算法时, 去解题的技巧及思路.
把一个整数和将这个整数减去1的整数进行按位与运算, 得到的结果是将该整数二进制位中最右边的1变为0.