LeetCode 371.两整数之和
题目描述
给你两个整数 a
和 b
,不使用 运算符 +
和 -
,计算并返回两整数之和。
举个例子:
输入:a = 1, b = 2
输出:3
视频题解
两整数之和
思路来源
思路来源
知识回顾
-
与
(&
)运算的规则1 & 1 = 1
1 & 0 = 0
0 & 1 = 0
0 & 0 = 0
两位同时为1
,结果才为1
。
-
或
(|
)运算的规则1 | 1 = 1
1 | 0 = 1
0 | 1 = 1
0 | 0 = 0
有一位为1
,结果就为1
。
-
异或
(^
)运算的规则1 ^ 1 = 0
1 ^ 0 = 1
0 ^ 1 = 1
0 ^ 0 = 0
两位不同,结果才为1
。
-
左移
运算符<<
,可以将一个对象的二进制向左移n
位,左边n
位丢弃,右边n
位补0
。比如,a = 1101
。a << 2 = 0100
-
右移
运算符>>
,可以将一个对象的二进制向右移n
位,右边n
位丢弃,左边n
位补0
。比如,a = 1101
。a >> 2 = 0011
思路解析
正常的十进制加法是加数和被加数每一位相加然后加上上一位的进位数,大于10
就继续进位。 题目要求不使用加法运算符 ,所以我们只能通过异或
(^
)、与
(&
)、左移
(<<
)等位运算来实现。
加数和被加数对应的二进制按位相加,1 + 1
对应位变成0
,1 + 0
对应位变成1
,0 + 0
对应位变成0
,这个可以通过异或
(^
)运算来实现。
那么还有进位怎么处理呢?
继续观察会发现加数和被加数对应的二进制按位相加,只有1 + 1
会存在进位1
,可以通过与
(&
)和左移
(<<
)运算来实现。
根据上述规律,对于a
,b
两个整数,我们可以得到算法如下:
temp_add = a ^ b
,获取到每一位的和(不包含进位),进入步骤2
。temp_carry = (a & b) << 1
,获取到每一位的进位,进入步骤3
。- 如果进位
temp_carry
为0
,最终结果就是temp_add
。如果进位temp_carry
不为0
,a = temp_add
,b = temp_carry
,进入步骤1
。
C++代码
cpp
class Solution {
public:
int getSum(int a, int b) {
while (b) {
int temp_add = a ^ b; //不包含进位a、b每位的和
//a、b每位和的进位,左移有符号值会溢出,赋给无符号的会自动取模
unsigned int temp_carry = (unsigned int)(a & b) << 1;
a = temp_add; //a、b每位的和赋值给a
b = temp_carry; //a、b每位的进位赋值给b
}
return a;
}
};
java代码
java
class Solution {
public int getSum(int a, int b) {
while (b != 0) {
int temp_add = a ^ b; // 不包含进位a、b每位的和
// a、b每位和的进位,左移有符号值会溢出,赋给无符号的会自动取模
int temp_carry = (a & b) << 1;
a = temp_add; // a、b每位的和赋值给a
b = temp_carry; // a、b每位的进位赋值给b
}
return a;
}
}
python代码
python
class Solution:
def getSum(self, a: int, b: int) -> int:
while b:
temp_add = a ^ b # 不包含进位a、b每位的和
# a、b每位和的进位,左移有符号值会溢出,赋给无符号的会自动取模
temp_carry = (a & b) << 1
a = temp_add # a、b每位的和赋值给a
b = temp_carry # a、b每位的进位赋值给b
return a
复杂度分析
时间复杂度: O(1) ,因为整数在32
位操作系统上占32
位,最多计算32
次temp_carry
,故为常数的时间复杂度。
空间复杂度: 只使用了几个整型变量,故空间复杂度为O(1)。