371. 两整数之和
我的思路
既然无法用加法,那么是不是可以用汇编add
(笑)?
class Solution {
public:
int getSum(int a, int b) {
__asm {
mov eax, a
mov ebx, b
add eax, ebx
mov a, eax
};
return a;
}
};
很不幸,Visual studio可以编译通过,LeetCode提交编译错误。
直觉:二进制。(直觉是一种很玄的东西)
如果是无进位加法的话,结果是两个数字的亦或,即 r e t = a ⨁ b ret = a \bigoplus b ret=a⨁b.
然后,差一步思考。
思路一
既然无进位加法是 a ⨁ b a \bigoplus b a⨁b, 那么只需要思考进位该如何处理即可。
假设当前需要相加的两个二进制位是: a , b a, b a,b. 当前位的结果为:低一位的进位 c a r r y carry carry + a + b a + b a+b. 同时,需要向高一位进位。设当前位是第 i i i 位。
a == 1 && b == 1
时,当前位需要向前面的一位进位,当前位的结果等于低位的进位:ret |= (carry << i)
,当前位的进位是1
。a == 1 || b == 1
时,当前位的结果是低位的进位和1
的异或:ret |= ((1 ^ carry) << i)
,进位不需要变化。(可以自己模拟一下)a == 0 && b == 0
时,当前位的结果是低位的进位:ret |= (carry << i)
,当前位的进位是0
。
因为在整形范围内,因此执行最多执行32
次即可完成。
AC代码:
class Solution {
public:
int getSum(int a, int b) {
int carry = 0;
int ret = 0;
for (int i = 0; i < 32; i ++){
int _a = (a >> i) & 1;
int _b = (b >> i) & 1;
if (_a == 1 && _b == 1){
ret |= (carry << i);
carry = 1;
}else if (_a == 1 || _b == 1){
ret |= ((1 ^ carry) << i);
}else{
ret |= (carry << i);
carry = 0;
}
}
return ret;
}
};
时间复杂度:
O
(
1
)
O(1)
O(1),执行32次。
空间复杂度:
O
(
1
)
O(1)
O(1),使用了可数个变量。
思路二
假设两个数字为6(100b)和13(1101b)。这两个数字的加法可以变成:1.无进位加法:6 ^ 13
,2.进位:6 & 13
,3.进位左移:(6 & 13) << 1
,4.将低位的进位和当前无进位结果相加。
在 C++ 的实现中,当我们赋给带符号类型一个超出它表示范围的值时,结果是 undefined;而当我们赋给无符号类型一个超出它表示范围的值时,结果是初始值对无符号类型表示数值总数取模的余数。因此,我们可以使用无符号类型来防止溢出。
使用unsigned int
防止溢出。
AC代码:
class Solution {
public:
int getSum(int a, int b) {
while (b){
unsigned int carry = (unsigned int)(a & b) << 1;
a ^= b;
b = carry;
}
return a;
}
};
时间复杂度分析:因为每一次左移都会将低位的0增加,因此最多执行32次,carry就会变成0.
O
(
1
)
O(1)
O(1).
空间复杂度分析:
O
(
1
)
O(1)
O(1)
2021.09.27 10:27
9.21号至9.25号的2022级研究生复试面试秘书A的工作结束了,有点小累。
昨天和周老师聊了一下,下午就从科工楼搬到了天际大厦。
离别总是太匆匆,都来不及说告别。
正式开启打工人的生活,不只是工位发生了变化,研究方向也转向区块链了。
慢慢来吧。