算法实战:位运算解决三题
35. 两个整数之和
题目描述
不使用运算符 + 和 -,计算两整数 a, b 之和。
解题思路与实现
这道题的核心在于理解计算机底层加法是如何通过位运算实现的。异或 ^ 本质上是【无进位加法】,而按位与 & 操作能得到【进位】的对应位置,但还需要左移 1 才是真正需要进位的位置。
我们需要一直循环,直到【进位】变成 0 为止。这就像我们手动做加法一样,先算本位,再处理进位,反复迭代直到没有进位产生。
class Solution {
public:
int getSum(int a, int b) {
// 解法:位运算 (^ 异或:无进位相加)
while (b) {
int x = a ^ b; // 无进位和
int y = (a & b) << 1; // 进位值,需左移一位
a = x;
b = y; // 将进位作为下一轮的加数
}
return a;
}
};
注意: 只进行一次 a & b 不一定保证新的 a 和 b 没有需要进位的位置,所以需要将这个步骤进行循环。当 a & b 为 0 时,说明没有进位的位置了,循环结束。
36. 只出现一次的数字 II
题目描述
给定一个非空整数数组,除了某个元素只出现一次以外,其余每个元素均出现了三次。找出那个只出现了一次的元素。
解题思路与实现
设要找的数为 ret。由于整个数组中,需要找的元素只出现了【一次】,其余的数都出现【三次】,因此我们可以根据所有数的【某一个比特位】的总和 % 3 的结果,快速定位到 ret 上的【一个比特位上】的值是 0 还是 1。
这样我们通过 ret 的每一个比特位上的值,就可以将 ret 还原出来。这种方法虽然时间复杂度是 O(32N),但非常巧妙且不需要额外空间。
class Solution {
public:
int singleNumber(vector<int>& nums) {
ret = ;
( i = ; i < ; i++) {
sum = ;
( x = ; x < nums.(); x++) {
sum += ((nums[x] >> i) & );
}
ret |= ((sum % ) << i);
}
ret;
}
};


