注意:凡是以英文出现的,都是题目提供的,包括答案代码里的前几行。
题目:
Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.
Example:Given a = 1 and b = 2, return 3.
Credits:Special thanks to @fujiaozhu for adding this problem and creating all test cases.
希望看到这里的同学能够先思考,最好是能够自己写具体的实现,有更好的答案可以直接在下面评论。
解析:
既然规定不能用加减运算符,这个时候我们可以思考:计算机本身又是如何解决加法这个问题的呢?如果你听说过加法器这个东西,那么问题就比较好解决了。我们可以用逻辑运算来模拟加法。
首先,我们可以把十进制转化成二进制,我们需要一个具体的例子来分析。假设要计算12 + 29
(1100 + 11101)的和。
|十进制\位数|5|4|3|2|1|
|-|-|-|-|-|
|12|0|1|1|0|0|
|29|1|1|1|0|1|
现在的问题就变成了怎么解决二进制加法的问题。由于加数和被加数的位数不定,又是在做加法,那么问题必然要用到循环。
两个位的和可以通过执行两个位的XOR(^)
来获得。通过执行与(&)
的两个位,可以获得进位。也就是半加法器逻辑。
语句 | 第一次循环 | 二 | 三 | |
---|---|---|---|---|
while(b != 0) { | a = 01100, b = 11101 | 见上次 | 见上次 | 结束 |
int carry = a & b | carry = 1100 | carry = 10000 | carry = 0 | |
a = a ^ b | a = 10001(17) | a = 1001(9) | a = 101001(41) | |
b = carry << 1 | b = 11000(24) | b = 100000(32) | b = 0(0) | |
} | 17 + 24 = 41 | 9 + 32 = 41 | 41 + 0 = 41 |
Q: 为什么是 carry << 1?
通过上面表格的分析,相信大家可以看到,每一列的 a + b 都等于 最终的结果。Why?这个算法本质上就是把有进位的和无进位的分开加。
a ^ b
是计算无进位的和。a & b
就是计算有进位的和。有进位的情况只有一种:两个相加的位同时为1,他们的和自然就是原来的2倍,也就是carry << 1
。比如:1101(13) + 1101(13) = 11010(26)。
答案:
class Solution {
public:
int getSum(int a, int b) {
while (b != 0) {
int carry = a & b;
a = a ^ b;
b = carry << 1;
}
return a;
}
};