剑指Offer-15-二进制中1的个数/力扣191-位1的个数
位运算
基础概念
- 与:&(有0为0)
- 或:|(有1为1)
- 异或:^(相同0,不同1)
- 非:~(取反)
- 左移:相当于乘2;在左移n位时,最左边的n位将被丢弃,右边补上n个0
- 右移:相当于除2;在右移n位时,最右边的n位将被丢弃,左边补位分为两种情况,无符号数补0,有符号数补符号位(1)
使用技巧
1. 判奇偶
(x&1)
:将被测数与1做”与“运算,判断数的(二进制)最后一位是0还是1
string judge(int num) { // 比较运算符的优先级高于位运算符号 if ((num & 1) == 0) { // 数的二进制末位为0 // 那么这里就有一个隐式的”转二进制“操作? return "even"; } else { return "odd"; } } int main() { cout << judge(100) << endl; cout << judge(7) << endl; cout << judge(-4) << endl; return 0; }
2. 不适用额外变量,交换两数
void swap(int &a, int &b) { a ^= b; b ^= a; // b=b^a=b^(a^b)=(b^b)^a=0^a=a // 一个数异或0等于它本身 a ^= b; // a=a^b=(a^b)^a=0^b=b } int main() { int a = 1, b = -8; swap(a, b); cout << "a=" << a << " b=" << b; //cout << (7 ^ 2);// =5? // 两个不同的数异或=无进制加法 // 二进制111^10=101=5 return 0; }
3. 异或可以被当做无进位加法使用,与操作可以用来获取进位
题目
可能引起死循环的解法
书上给出了一种可能引起死循环的解法,是这样的:
- 判断低位是否为1
- 将数右移一位
- 重复以上步骤
引起死循环的原因则是,当二进制数为负数时,右移操作后高位便会补1,最终数字变成全是1(0xFFFFFFFF)并持续进行下去
常规解法
为了避免上面的情况发生,那么不要右移原数字,而是左移1(由低到高用来”与“每一位来判1)
class Solution { public: int hammingWeight(uint32_t n) { int count = 0; unsigned int flag =1; // 循环次数等于整数二进制的位数 // 即1从低位移到了高位 while(flag){ if(n&flag) count++; // 当与运算结果为1,即当前位为1 // 与运算是默认和低位进行的吗? // 不是二进制则转换成二进制在进行运算吗 flag<<=1; } return count; } };
但很明显,大多数情况下执行了不必要的循环次数
最优解
分析到一种情况,将一个二进制数减一,则:
- 最右边的1变为0,它右边有0则变1,左边不变
在与原整数做”与运算“
总结下来是:把一个整数减一再与原整数做”与“运算=把该整数最右边的1变为0
那么有多少个1就可以进行多少次这样的操作了
class Solution { public: int hammingWeight(uint32_t n) { int count = 0; while(n){ // 当原整数中所有的1都变成0的时候,循环结束 ++count; n=(n-1)&n;// 相当于把最右边的1变为0 } return count; } };
就是用某种位操作消从最右边开始消1
本文作者:YaosGHC
本文链接:https://www.cnblogs.com/yaocy/p/16252584.html
版权声明:本作品采用知识共享署名-非商业性使用-禁止演绎 2.5 中国大陆许可协议进行许可。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步