目录
- 常见位运算总结
- 1. 位1的个数
- 2. 比特位计数
- 3. 汉明距离
- 4. 只出现一次的数字
- 5. 只出现一次的数字Ⅲ
- 6. 判定字符是否唯一
- 7. 丢失的数字
- 8. 两正数之和
- 9. 只出现一次的数字Ⅲ
- 10. 消失的两个数字
常见位运算总结
重点 :
1. 位1的个数
算法思路:
这道题就用到了我们总结的那个第七个方法, 干掉最右侧的1, 知道全部为0位置, 记录并返回干掉次数即可.
class Solution {
public:int hammingWeight(int n) {int ret = 0;while(n){n &= (n-1);ret++;}return ret;}
};
法二: 遍历每一位进行按位与操作, 并没有方法一效率高
class Solution {
public:int hammingWeight(int n) {int ret = 0;for(int i = 0; i < 32 ; i++){if((n & 1) == 1) ret++;n >>= 1;}return ret;}
};
2. 比特位计数
算法思路: 本题也就是求出0到n中每一个数的比特位中1的个数, 很容易想到的方法就是,遍历数组, 按照上一题的思路求出i的1比特位即可.
class Solution {
public:vector<int> countBits(int n) {vector<int> ans;for(int i = 0 ; i <= n; i++){int tmp = i, ret = 0;while(tmp){tmp &= (tmp - 1);ret++;}ans.push_back(ret);}return ans;}
};
3. 汉明距离
算法思路:
也就是求出两个数的比特位不同的个数, 首先对两正数进行异或运算, 不同为1, 然后求出tmp中1的个数, 沿用之前的方法, 先找出最右侧的1, 然后干掉最右侧的1, 记录次数即可.
class Solution {
public:int hammingDistance(int x, int y) {int ret = 0;int tmp = x ^ y;while(tmp){tmp &= (tmp-1);ret++;}return ret;}
};
4. 只出现一次的数字
算法思路: 仅需将所有数字进行异或, 相同的就被消去了, 最后的数字即为结果.
class Solution {
public:int singleNumber(vector<int>& nums) {int ret = 0;for(int i = 0; i < nums.size(); i++){ret = ret ^ nums[i];}return ret;}
};
5. 只出现一次的数字Ⅲ
算法思路: 首先将数组进行异或处理, 结果就是最后两个不同的数字异或的结果, 因为这两个数字不相同, 所以一定有比特位异或的结果为1, 我们仅需据此进行划分为两组即可, 这里我们默认查找最右侧的1, 然后据此进行划分, 分别进行异或, 最后返回分别异或的结果.
class Solution {
public:vector<int> singleNumber(vector<int>& nums) {int ret = 0, tmp = 0;for(auto& e : nums)tmp ^= e;int pos = -1;for(int i = 0; i < 32; i++){if((tmp & 1) == 1){pos = i;break;}tmp = tmp >> 1;}int x1 = 0,x2 = 0;for(auto& e : nums){if(((e >> pos) & 1) == 1)x1 ^= e;else x2 ^e;}return {x1,x2};}
};
6. 判定字符是否唯一
本道题可以采用位图的方法进行优化, 因为数据范围只有小写字母, 我们进行一个int的比特位当成哈希表来用即可, 1和0进行两种状态的标记, 处理之前还可以使用鸽巢原理进行一下优化, 也就是26个字母如果字符串长度超过26那么一定有相同的字符串, 这时候直接返回false即可
class Solution {
public:bool isUnique(string astr) {int n = astr.size();if(n > 26) return false;int bitmap = 0;for(auto& x : astr){int l = x - 'a';if(((bitmap >> l) & 1) == 1)return false;bitmap |= 1 << l;}return true;}
};
7. 丢失的数字
算法思路: 仅需进行异或操作, 将ret和数组进行异或并且和0到size之间的所有i进行异或即可.
class Solution {
public:int missingNumber(vector<int>& nums) {int ret = 0;for(int i = 0; i <= nums.size(); i++)ret ^= i;for(auto x : nums)ret ^= x;return ret;}
};
8. 两正数之和
算法思路: 本题要求不能使用+ 和 - 运算符将两个数进行相加, 开始总结位运算的时候, 我们也说过^表示的就是我进位相加, 但是进位怎么办, 两数&的结果即为进位, 但是进位并不是加到本位上的, 应该加到前一位, 所以结果我们要进行左移然后相加, 那么问题又来了, 不让使用+怎么进行相加呢, 其实我们在重复上面的操作, 循环即可, 直到进位为0.
class Solution {
public:int getSum(int a, int b) {while(b != 0){int add = a ^ b;int carry = (a & b) << 1;a = add;b = carry;}return a;}
};
9. 只出现一次的数字Ⅲ
算法思路: 理解题意即可知, 这些数字的每一个bit为相加的结果要么是三的倍数,也就是ret的这一位是0, 要么被三整除余数为1, 也就是ret的这一位是1
class Solution {
public:int singleNumber(vector<int>& nums) {int ret = 0;for(int i = 0; i < 32; i++){int sum = 0;for(auto x : nums)sum += ((x >> i) & 1);if(sum % 3 == 1)ret |= (1 << i);}return ret;}
};
10. 消失的两个数字
算法思路: 首先先将nums中的每一个数和0到N之间每一个数进行异或, 结果为两个数异或的结果, 然后找出1那个位置, 进行划分即可, 分成两组, 再次进行分别异或, 即可得出结果.
class Solution {
public:vector<int> missingTwo(vector<int>& nums) {int tmp = 0;for(int i = 1; i <= nums.size() + 2; i++)tmp ^= i;for(auto x : nums)tmp ^= x;int dif = 0;while(1){if(((tmp >> dif) & 1) == 1) break;dif++;}int a = 0, b = 0;for(int i = 0; i <= nums.size()+2; i++){if(((i >> dif) & 1) == 1)a ^= i;else b ^= i;}for(auto x : nums){if(((x >> dif) & 1)== 1)a ^= x;else b ^= x;}return {a,b};}
};
完