概述
位运算是算法题里比较特殊的一种类型,它们利用二进制位运算的特性进行一些奇妙的优化和计算。常用的位运算符号包括:“∧” 按位异或、“&” 按位与、“|” 按位或、“∼” 取反、“<<” 算术左移和 “>>” 算术右移。以下是一些常见的位运算特性:
异或 | 与 | 或 |
---|---|---|
x ^ 0000 = x | x & 0000 = 0 | x | 0000 = x |
x ^ 1111 = ~x | x & 1111 = x | x | 1111 = 1111 |
x ^ x = 0 | x & x = x | x | x = x |
除此之外, n & (n - 1) 可以去除 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,减去 1 得到 11110011,这两个数按位与得到 11110000。
n & (-n) 可以仅保留 n 的位级表示中最低的那一位,例如对于二进制表示 11110100,取负得到 00001100,这两个数按位与得到 00000100。
回顾一下移位操作,移位操作是一种基本操作,是一种直接对二进制数据的位运算操作,移位运算又包含了逻辑移位(logical shift)和算术移位(arithmetic shift)两种。
- 逻辑移位:移出去的位丢弃,空缺位(vacant bit)用 0 填充。
- 算术移位:移出去的位丢弃,空缺位(vacant bit)用“符号位”来填充,所以一般用在右移运算中。
无符号数,不管是左移还是右移都是逻辑移位;有符号数,做左移运算是逻辑移位,而做右移运算是算术移位。
461 汉明距离
给定两个十进制数字,求它们二进制表示的汉明距离(Hamming distance,即不同位的个数)。
输入是两个十进制整数,输出是一个十进制整数,表示两个输入数字的汉明距离。
输入:x = 1, y = 4
输出:2
解释:1 (0 0 0 1);4 (0 1 0 0)
解析:
求二进制数不同位的个数,直接使用将俩个数进行按位异或操作,不同位的结果就是 1,所以最终统计异或结果中的 1 的个数即可。
计算二进制数 1 的个数的方法:不断将二进制数算数右移,将其与 1 进行与运算,如果末位是 1 则加入计数。
class Solution {
public:
int hammingDistance(int x, int y) {
// 异或运算
int diff = x^y;
int ans = 0;
while(diff){
// 与运算 判断末位是否为 1
ans += diff & 1;
// 算术右移动 将已经被统计的 1 移出
diff = diff>>1;
}
return ans;
}
};
190 颠倒二进制位
给定一个十进制整数,输出它在二进制下的翻转结果。
输入和输出都是十进制整数。
输入:n = 00000010100101000001111010011100
输出:964176192 (00111001011110000010100101000000)
解释:将 n 的二进制串倒转
解析:
使用算术左移和右移,可以很轻易地实现二进制的翻转。保存结果的二进制串每次向左移动一位腾出末位,然后将 n 与 1 取出 n 的末位并放入结果腾出的末位,放入之后 n 向右移动一位将已放入的位移出。
一个简单的示例:
1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|
ans (算术左移) | 0000 | 0000 | 0001 | 0010 | 0101 |
n (算术右移) | 1010 | 0101 | 0010 | 0001 | 0000 |
class Solution {
public:
uint32_t reverseBits(uint32_t n) {
// 无符号32位整型
uint32_t ans = 0;
for(int i=0;i<32;++i){
// 每次先将结果左移一位腾出位置
ans <<= 1;
// 将 n 当前的最后一位放到上一步ans腾出的位置(末位)
ans += n&1;
// 将已经放入结果的位移出
n >>= 1;
}
return ans;
}
};
693 交替位二进制数
给定一个正整数,检查它的二进制表示是否总是 0、1 交替出现
输入一个整数,输出一个布尔类型表示二进制表示是否总是 0、1 交替出现
输入:n = 10
输出:true
解释:10 的二进制表示是:1010
解析:
一种简单的思路是不断使用算术右移将n的二进制表示末位移出,使用按位与运算获取末位是0还是1,并且比较第 i 个和第 i-1 个末位是否相同,如果相同则直接返回false,检查完成则返回true。
class Solution {
public:
bool hasAlternatingBits(int n) {
// 记录第一个末位
int pre = n & 1;
n>>=1;
while(n){
// 比较第 i 个和第 i-1 个末位
int now = n & 1;
if(now == pre){
return false;
}else{
// 更新前一个状态
pre = now;
}
n >>= 1;
}
return true;
}
};
参考资料
LeetCode 101:和你一起轻松刷题(C++) 第 10 章 神奇的位运算
最后
以上就是光亮缘分为你收集整理的LeetCode刷题笔记 位运算巧解算法题 位运算基础的全部内容,希望文章能够帮你解决LeetCode刷题笔记 位运算巧解算法题 位运算基础所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复