-
题目:
一个uint32_t数n,返回n在计算机中的二进制表示中1的个数; -
思路:
1.循环取二进制的最低位,并右移;O(logn):n每次除2,logn次循环后为0,(实际上更确切的说,logn指n的二进制表示中最高位1所在的位数(例如log16 = 4)),O(1)
无符号数在计算机中,无论左移还是右移都是逻辑移位,即补0;
n & 1:取到n的二进制表示的最低位
n >> 1:逻辑右移,在左边补0
循环取n的二进制表示的最低位,直至n==0;
class Solution {
public:
int hammingWeight(uint32_t n) {
int res = 0;//统计1的个数
while (n) {
res += n & 1, n >>= 1;//n&1得到n的二进制表示的最低位;n>>1
}
return res;
}
};
2.(借鉴大佬的做法)巧用n & (n -1):O(m):m表示n的二进制中1的个数,O(1)
n & (n - 1)可以把n的最低位1变成0;
class Solution {
public:
int hammingWeight(uint32_t n) {
int res = 0;//统计1的个数
while (n) {
n &= (n - 1);//每次把n的最低位的1变成0
++res;
}
return res;
}
};
附注:若本题给的n时有符号整数,难度增加:
3.在C++中如果我们右移一个负整数,系统会自动在最高位补1,这样会导致 n 永远不为0,就死循环了;
解决办法是把 int强制转化成unsigned int,这样 n 的二进制表示不会发生改变,但在右移时系统会自动在最高位补0,最终n会变成0退出循环;
class Solution {
public:
int NumberOf1(int n) {
unsigned int un = n;//核心所在,转换位unsigned int后,就跟前面这道题一样了,用1和2均可
int res = 0;
while (un) {
res += (un & 1);
un >>= 1;
}
return res;
}
};
- 总结:
1.同一类型的unsigned和signed的二进制表示是不变的,变的是计算机的解释方法不同:实际就是最高位的权值一正一负,例如把有符号数-1转换成unsigned int后,二者的二进制表示都是11111111 11111111 11111111 11111111,但最高位1的权重一个是2 ^ 31,一个是 - 2 ^ 31;
2.n & 1可以得到n的二进制的最低位,配合右移使用;