Calculate the sum of two integers a and b, but you are not allowed to use the operator +
and -
.
Example 1:
Input: a = 1, b = 2 Output: 3
Example 2:
Input: a = -2, b = 3 Output: 1
Credits:
Special thanks to @fujiaozhu for adding this problem and creating all test cases.
這道題是 CareerCup 上的一道原題,可參見博主之前的博客 18.1 Add Two Numbers。這里讓實現兩數相加,但是不能用加號或者其他什么數學運算符號,那么只能回歸計算機運算的本質,位操作 Bit Manipulation,在做加法運算的時候,每位相加之后可能會有進位 Carry 產生,然后在下一位計算時需要加上進位一起運算,那么能不能將兩部分拆開呢,來看一個例子 759+674
1. 如果不考慮進位,可以得到 323
2. 如果只考慮進位,可以得到 1110
3. 把上面兩個數字假期 323+1110=1433 就是最終結果了
然后進一步分析,如果得到上面的第一第二種情況,在二進制下來看,不考慮進位的加,0+0=0,0+1=1, 1+0=1,1+1=0,這就是異或的運算規則,如果只考慮進位的加 0+0=0, 0+1=0, 1+0=0, 1+1=1,而這其實這就是'與'的運算,而第三步在將兩者相加時,再遞歸調用這個算法,終止條件是當進位為0時,直接返回第一步的結果。一切都是如此的美好,突然有一天,博主的所有方法都無法通過 OJ 了,不知為何,原因不明。在熱心網友 GGGGITFK 的提示下,終於知道了錯誤的原因:
runtime error: left shift of negative value -2147483648,對INT_MIN左移位。
就是 LeetCode 自己的編譯器比較 strict,不能對負數進行左移,就是說最高位符號位必須要為0,才能左移(此處應有尼克楊問號臉?!),好吧,你贏了。那么在a和b相 '與' 之后,再'與'上一個最高位為0,其余位都為1的數 0x7fffffff,這樣可以強制將最高位清零,然后再進行左移,終於,世界清靜了,參見代碼如下:
解法一:
class Solution { public: int getSum(int a, int b) { if (b == 0) return a; int sum = a ^ b; int carry = (a & b & 0x7fffffff) << 1; return getSum(sum, carry); } };
上面的解法可以精簡到一行,哈哈,叼不叼?
解法二:
class Solution { public: int getSum(int a, int b) { return b == 0 ? a : getSum(a ^ b, (a & b & 0x7fffffff) << 1); } };
也可以寫成迭代的樣子,思路都是一樣的~
解法三:
class Solution { public: int getSum(int a, int b) { while (b) { int carry = (a & b & 0x7fffffff) << 1; a = a ^ b; b = carry; } return a; } };
Github 同步地址:
https://github.com/grandyang/leetcode/issues/371
類似題目:
參考資料:
https://leetcode.com/problems/sum-of-two-integers/