题目: 写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例:
输入: a = 1, b = 1
输出: 2
提示:a, b 均可能是负数或 0;结果不会溢出 32 位整数
思路:
1. 推导思路:
不让用四则运算,那么只能用位运算,这个大部分人都能想到,但是咋用我想了很久都没想到😂,当时就感觉这个有点像模电里面的全加器,全加器就是利用门电路,也就是位运算实现的,先异或算出值,再加上进位得到结果。那么我们就按照全加器来分析一下加法如何实现:
我们先拿十进制举例:现在有5+17=22,
- 我们先把5和17的个位,不包含进位的的结果求出为:7+5=2(不包含进位)1+0=1,所以为12;
- 再得到进位10。
- 最后相加为:12+10=22。
我们下面分析二进制:5的二进制为101,17为10001。
- 我们先不管进位,即遵循:0+0=0,1+0=1,0+1=1,1+1=0 来算,那么结果为:10100。
- 得到进位,我们知道只有1+1时才会发生进位,进位为10。
- 相加为:10100+10=10110,十进制为22。
通过上面得分析,我们知道相加需要三步:得到无进位的值,进位,相加。那么我们需要用位运算将这三步表示出来,我们列个表格来看一下数值和无进位值,进位的关系:
a | b | 异或运算 | 无进位n | 与运算 | 进位c,加粗表示 |
---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 00 |
0 | 1 | 1 | 1 | 0 | 00 |
1 | 0 | 1 | 1 | 0 | 00 |
1 | 1 | 0 | 0 | 1 | 10 |
上表我们可以得到n和c如何用位运算得到:第一步:n=a⊕b,第二步:c=(a&b)<<1
对于c的表示肯定有人存在疑惑,我当时也很迷惑,进位一般是存在低位向高位进位,那么如果在二进制中有:
第三步:将n和c相加,n和c相加的做法和a+b一样,所以有a=n,b=c,一直循环,当b为0时即没有进位时,那么a就是答案。
2. 负数问题: 负数情况下三步走也是可以的,因为呢,在计算机系统中,数值一律用补码来表示和存储。那么 加法、减法可以统一处理(CPU只有加法器)。因此,以上方法同时适用于正数和负数的加法 。
3. 演示: 我们按照三步走思路来演示一下过程,只有了解过程才可以写出代码:
(1)5+17=22,我们用8位一个字节来表示演算:
(2)我们再举一个负数的例子:3+(-8)=-5
4. 代码:
那么我们写出代码就很简单了,按照三步思路即可。注意力扣编译器不支持有符号整型左移,所以要先强转为无符号的,但是visual支持。时间空间复杂度均为O(1)
int add(int a, int b)
{
int n,s;
while(b!=0)
{
n=a^b;//无进位值
s=((unsigned int) (a&b)<<1);//进位
//visual支持:s=(a&b)<<1;
//将n和c进行加法
a=n;
b=s;
}
return a;
}
int main()
{
cout<<add(1,1);
}
加油哦!🥘火锅快乐。