[LeetCode] 371. Sum of Two Integers
Given two integers a
and b
, return the sum of the two integers without using the operators +
and -
.
Example 1:
Input: a = 1, b = 2 Output: 3
Example 2:
Input: a = 2, b = 3 Output: 5
Constraints:
-1000 <= a, b <= 1000
两整数之和。
给你两个整数 a
和 b
,不使用 运算符 +
和 -
,计算并返回两整数之和。
思路是位运算,但是非常难想,需要复习。我是参考了这个帖子和这个帖子才想通了的。
a | b | 低位 | 进位 |
---|---|---|---|
0 | 0 | 0 | 0 |
1 | 0 | 1 | 0 |
0 | 1 | 1 | 0 |
1 | 1 | 0 | 1 |
首先注意到,任意两个数字a和b相加的时候,他们的低位和高位的结果是什么?如上图所示,你会发现一个规律,低位的结果是a^b(两数相同为0,两数不同为1),而进位的结果是a&b(两数相同为0,两数不同为1)。那么做法就是设两个变量lower和carry来分别记录两者相加的低位和高位。lower = a ^ b, carry = a & b,一轮结束后,如果carry = 0说明没有进位,则可以直接退出while循环并且返回lower;如果carry = 1则说明有进位,此时需要把低位赋予a,把carry左移一位的结果赋予b再做运算。例子,5 + 7的话,其实是101 + 111
a ^ b如下 = 相加各个位置上的值但是不计算进位
1 0 1
1 1 1
----
0 1 0
a & b如下 = 计算各个位置上的进位值
1 0 1
1 1 1
----
1 0 1,再向左移动一位,101 << 1 = 1010
重复上述两步,
a ^ b = 010 ^ 1010 = 0010 ^ 1010 = 1000
a & b = 010 & 1010 = 0010 & 1010 = 0010,左移一位,0010 << 1 = 0100
重复上述两步,
a ^ b = 1000 ^ 0100 = 1100
a & b = 1000 & 0100 = 0000,因为这里进位为0,可以跳出循环了,结果就是1100
时间O(1)
空间O(1)
JavaScript实现
1 /** 2 * @param {number} a 3 * @param {number} b 4 * @return {number} 5 */ 6 var getSum = function(a, b) { 7 if (a === 0) { 8 return b; 9 } 10 if (b === 0) { 11 return a; 12 } 13 while (b !== 0) { 14 let carry = a & b; 15 a = a ^ b; 16 b = carry << 1; 17 } 18 return a; 19 };
Java实现
1 class Solution { 2 public int getSum(int a, int b) { 3 if (a == 0) { 4 return b; 5 } 6 if (b == 0) { 7 return a; 8 } 9 int lower; 10 int carrier; 11 while (true) { 12 lower = a ^ b; // 计算低位 13 carrier = a & b; // 计算进位 14 if (carrier == 0) { 15 break; 16 } 17 a = lower; 18 b = carrier << 1; 19 } 20 return lower; 21 } 22 }
二刷我参考了一个更好理解的代码。对于一个 Integer,他只有32位,所以我们只需要计算这 32 位上应该分别是什么数字即可。那么我们遍历 32 次,每次我们分别把数字 a 和数字 b 在这一位上的 digit 取出来,设为 u1 和 u2。这里我们对每一位做加法,用 carry 存储进位。那么,
- 如果 u1 和 u2 都是 1,res 在这一位的二进制表达就是 0 (1 + 1 = 0),但是记住我们要把之前的进位 carry 带上,同时此时 carry = 1,因为当前位是有进位的
- 如果 u1 和 u2 其中只有一个是 1,那么 res 在这一位上的二进制表达是前一位的进位情况。而这里的抑或 XOR 操作,巧妙地执行了这个任务。因为 XOR 操作下,两者相同为 0,不同为 1
- 如果 u1 和 u2 都是 0,此时当前位是什么取决于前一位的进位情况
Java实现
1 class Solution { 2 public int getSum(int a, int b) { 3 int res = 0; 4 int carry = 0; 5 for (int i = 0; i < 32; i++) { 6 int u1 = (a >> i) & 1; 7 int u2 = (b >> i) & 1; 8 if (u1 == 1 && u2 == 1) { 9 res |= (carry << i); 10 carry = 1; 11 } else if (u1 == 1 || u2 == 1) { 12 res |= ((1 ^ carry) << i); 13 } else { 14 res |= (carry << i); 15 carry = 0; 16 } 17 } 18 return res; 19 } 20 }
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】博客园社区专享云产品让利特惠,阿里云新客6.5折上折
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步