位运算的介绍
运算符 | 名称及其规则 | 例子 |
~ | 取反(~1 = 0, ~0 = 1) | ~11101 = 10 |
& | 按位与(1&1 = 1, 0&1 = 1&0 = 0&0 = 0) | 11001 & 10100 = 10000 |
| | 按位或(1|1 = 0|1 = 1|0 = 1, 0|0 = 0) | 1001 | 10 = 1011 |
^ | 按位异或(0^1 = 1^0 = 1, 0^0 = 1^1 = 0) | 101001 ^ 11000 = 1001 |
<< | 左移 | 1000 << 1 = 10000 |
>> | 右移 | 1000 >> 1 = 100 |
位运算的一些使用
异或,与,或都满足交换律和结合律:
a^b = b^a, a^b^b= a^(b^b), a&b = b&a, a&b&b = a&(b&b),a|b = b|a, a|b|b = a|(b|b)
判断一个数a是否为偶数,一般为 a % 2 == 0。还可以用为运算实现:a&1 == 0
判断一个数是否为2的次幂 x&(x - 1) == 0 (等于0是)
a<<i = a * pow(2, i) a>>i = a/pow(2, i) (i + j) / 2 还可以表示为 (i + j) >> 1
0^a = a, a^a = 0, a^b^b = a
异或可以完成不进位的加运算:11001 ^ 10000 = 01001
例题一:只出现一次的数字(力扣 136 简单)
题目链接:136. 只出现一次的数字 - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/single-number/
题目:给定一个非空整数数组,除了某个元素只出现一次以外其余每个元素均出现两次。找出那个只出现了一次的元素。
示例 1:
输出:[ 2, 2, 1]
输出:1
示例 2:
输入:[ 4, 1, 2, 1, 2]
输出:4
题目分析:
异或的运算满足交换律和结合律, 而且 a^0 = a, a ^ a = 0, a ^ b ^ a = b ^ b ^ a = a, 在数组中只有一个数只出现一次, 其余的都出现了两次,将数组中的全部数都异或一次即可找出只出现一次的数。
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int ans = 0;
for(int i = 0; i < nums.size(); i ++)
ans ^= nums[i];
return ans;
}
};
例题 2:只出现一次的数字II(力扣 137 中等)
题目链接:137. 只出现一次的数字 II - 力扣(LeetCode) (leetcode-cn.com)https://leetcode-cn.com/problems/single-number-ii/
题目:给你一个数组nums,除某个元素仅出现一次外,其余每个元素都恰出现三次。请你找出并返回那个只出现一次的元素。
示例 1:
输入:nums = [ 2, 2, 3, 2]
输出:3
示例 2:
输入:nums = [ 0, 1, 0, 1, 0, 1, 99]
输出:99
题目分析:除了一个数只出现一次其余每个数都出现了三次,可以将每个数转化为32二进制, 对 每个二进制对应的数进行求和,并且对3取模。因为其他出现了三次,如果一个位的和对3取模对于1, 那么只出现的一次的数可以找到在这个位置存在。例如[ 3, 3, 3, 4] , 这些数变为32位二进制数就是[0000000000000000000000000000011, 0000000000000000000000000000011, 0000000000000000000000000000011, 0000000000000000000000000000100],将这些数的每一位的数进行求和得到0000000000000000000000000000133,对每位数对3取模得到0000000000000000000000000000100,等于4。
代码:
class Solution {
public:
int singleNumber(vector<int>& nums) {
int n = nums.size(), ans = 0;
for(int i = 0; i < 32; i ++)
{
int sum = 0;
for(int j = 0; j < n; j ++)
sum += (nums[j] >> i) & 1;
if(sum % 3 == 1)
ans |= (1 << i);
}
return ans;
}
};