位运算的运算对象只能是整型或者字符型数据。
C++ 的位运算符:
- 按位与: &
- 按位或: |
- 按位异或: ^
- 按位取反: ~
C++中的移位运算:
移位运算是指将二进制信息串作为整体移动。
- 左移运算符: 低位补0,高位被移出来的位抛弃,左移1位在左移没有丢失高位信息的情况下相当于乘以2.
- 右移运算符: 与左移相反,对于小整数,每右移1位,相当于除以2。在右移时,需要注意符号位问题。对无符号数据,右移时,左端空出的位用0补充。对于带符号的数据,如果移位前符号位为0(正数),则左端也是用0补充;如果移位前符号位为1(负数),则左端用0或用1补充,取决于计算机系统。对于负数右移,称用0 补充的系统为“逻辑右移”,用1补充的系统为“算术右移”。
Leetcode上位运算的几道例题
1、位异或运算
异或运算: 相同为0,不同为1。将数组中的所有元素求异或和,对于相同的元素,异或的结果为0。因此,数组中成对出现的元素异或和为0,所有元素的异或和即为只出现一次的元素。
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans = nums[0];
for(int i = 1; i < nums.size(); i++) {
ans ^= nums[i];
}
return ans;
}
};
2、位异或运算2
一个整型数组 nums 里除两个数字之外,其他数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
分析:
有了例题1的经验,我们可以想到:如果将整型数组nums分为两个组,分组满足
- 两个只出现一次的数字被分到不同的组
- 相同的数字分到相同的组
那么,只需要对这两个组分别做一次异或和运算,得到的结果就是两个只出现一次的数字。
关键来了,如何进行分组呢?
**取整型数组异或和为1的那一位,为1的分为一组,为0的分为一组,是否满足上面两个条件: **
- 相同的数字,对应的位肯定相同,因此相同的数字肯定能分到相同的组
- 因此异或的运算法则是相同为0,不同为1,因此这一位来看,这两个只出现一次的数字的对应位肯定一个是1,一个是0,最终异或的结果才能为1。因此,可以将这两个只出现一次的数字被分到不同的组
代码实现如下:
class Solution {
public:
vector<int> singleNumbers(vector<int>& nums) {
// 求异或和
int ans = nums[0];
for(int i = 1; i < nums.size(); i++) {
ans ^= nums[i];
}
// 找到异或和结果中为1的那一位
int div = 1;
while((ans & div) == 0)
div = div << 1;
// 分组
int a = 0, b = 0;
for(int i = 0; i < nums.size(); i++) {
if((div & nums[i]) == 0) {
a ^= nums[i];
}
else {
b ^= nums[i];
}
}
return vector<int>{a, b};
}
};