题目来自 力扣(LeetCode)
题目描述
不使用运算符+
和-
,计算两整数 a
、b
之和。
示例
示例 1:
输入: a = 1, b = 2
输出: 3
示例 2:
输入: a = -2, b = 3
输出: 1
分析
第一眼看到题目就心想,这不是很简单么,异或、位运算,不就行了?
看了第二眼,为什么异或就能解决这个问题呢!?
异或 ^ 1
相异为一
A | B | A^B |
---|---|---|
1 | 0 | 1 |
1 | 1 | 0 |
0 | 1 | 1 |
0 | 0 | 0 |
通过观察异或运算的真值表,与加法的真值表特别地像。需要注意的是异或只看本位,加法可能需要进位。从而用到与运算&。
与 &
全一为一
A | B | A&B |
---|---|---|
1 | 0 | 0 |
1 | 1 | 1 |
0 | 1 | 0 |
0 | 0 | 0 |
与运算可以很好地解决加法进位的问题,加法进位和与运算结果对应:1+0、0+1、0+0的进位都是0,1+1的进位为1。
通过异或得到了本位和,通过与运算得到了进位值,最后,只需要将进位值给高一位即可。
左移 <<
挺好理解的,将进位值左移到高位参与加法运算。
不管是无符号数,还是有符号数,不管是正数,还是负数,左移都是所有位参与,高位舍弃,低位补零。
-
如果b为0,结果为a
-
否则,将a^b的结果(每一位的本位和)与a&b后左移一位的结果(每一位的进位)相加(递归\迭代)。
注意
LeetCode中国版的C++好像不支持负值左移,会报错:
runtime error: left shift of negative value -2147483648 (solution.cpp)
需要强转为无符号数(unsigned int)。
代码
C++:
//C++
class Solution {
public:
int getSum(int a, int b) {
return b==0? a:getSum(a^b, (unsigned int)(a&b)<<1);
}
};
补充
牛客网《剑指Offer》上有一道类似的题目(支持负值左移)不用加减乘除做加法。
顾名思义,不一样(异)的话就或运算,一样的话就得零。二进制只有0和1,或运算得到1。即,相异为一。 ↩︎