牛客网:JZ65 不用加减乘除做加法(详解)
前言:本期是关于JZ65 不用加减乘除做加法的详解,内容包括四大模块:题目,代码实现,大致思路,代码解读,今天你c了吗?
题目:
描述
写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。
数据范围:两个数都满足−10≤n≤1000
进阶:空间复杂度 O(1),时间复杂度O(1)
示例1
输入:
1,2
返回值:
3
示例2
输入:
0,0
返回值:
0
代码实现:
int Add(int num1, int num2 )
{
// write code here
while(num2!=0)
{
int tmp = num1^num2;
num2 = (num1&num2)<<1;
num1 = tmp;
}
return num1 ;
}
大致思路:
1. 用户输入的两数是十进制数字,但在计算机中存储的是二进制形式,故而相加减都是以两数的二进制形式进行的
2. 举个例子:输入 5 7,求5+7,结果是12
算法(十进制版):
a. 求出两数不进位相加的结果
b. 求出两数应该进的位
c. 两数之和=两数不进位相加的结果+两数应该进的位
5+7= 2 + 10 =12
5+7不进位的结果 5+7应该向前进一位(在个位向前进一位得到一个十)
我们真正要使用的是二进制版的算法
算法(二进制版):
5的二进制形式:0101 7的二进制形式:0111
现求5+7 起始就是求 0101+0111
两个二进制数相加(比如 0101+0111)的求和算法:
1. 求出0101和0111不进位相加的结果:(二进制是逢2进1)
不进位即:1+1=0(因为逢2进1),0+0=0,0+1=1
演示:0 1 0 1
+ 0 1 1 1
结果:0 0 1 0
0101和0111不进位相加的结果可以通过两数异或^得到
按位异或^ : 相同则0,相异则1
2. 求出0101和0111应该进的位:
step1:找包含出能产生进位效果的比特位的二进制数
(即找出两二进制数所对应比特位上都是1的)
step2:将包含出能产生进位效果的比特位的二进制数运用左移操作符
即可得到0101和0111应该进的位
3. 0101和0111不进位相加的结果+两数应该进的位
又是两个二进制形式的数相加,重复两个二进制数相加的算法
直至两个二进制数应该进的位变成0,循环结束
代码解读:
int Add(int num1, int num2 )
{
// write code here
while(num2!=0)
{
int tmp = num1^num2;
num2 = (num1&num2)<<1;
num1 = tmp;
}
return num1 ;
}
num1和num2在内存中以二进制的形式存储
num1:存储两二进制数不进位相加(按位异或^)的结果
num2:存储两二进制数应该进的位(按位与&后再左移<<1位)
简洁版:
1.两二进制相加,只要两二进制应该进的位不为0,
则就要继续另外一对二进制数的相加(新的原身)
另外的一对二进制数:两原身二进制数不进位相加的结果和两原身二进制数应该进的位
另外一对二进制数的相加就要求出这另外一对二进制数
a. 两原身二进制数按位异或得到 b. 两原身二进制数按位与后再左移1位得到
2. 当在一对二进制的相加中,它们进的位位0了,则计算完毕,结束while循环
形象一点:将原来相加的二进制数0101和0111想象成掌权者,掌权者位置有两个,掌权者1的位置上是上一任掌权者们不进位相加的结果,掌权者2的位置上是上一任掌权者们应该进的位,
当掌权者2的位置上的数值不为0时,表示国力强盛,扩张了领土,需要产生另一对掌权者治理
故而掌权者1位置上的数值和掌权者2位置上的数值要产生和它们同源的新的掌权者,继承扩张领土上的两个掌权者位置
当掌权者2位置上的数位0时,表示全部领土已扩张完毕。
解析版:我们以(5)0101+0111(7)的求和为例:
1. 得到两二进制数按位异或(两二进制数不进位相加)的结果存储至tmp中
0101^0111 -> 0010
以易理解的十进制视角:
5+7不进位的结果是2,即按位异或所得的二进制0010转化成十进制就是2
2. 得到两二进制数应该进的位:
a. 首先求出包含产生进位效果的比特位的二进制数:两二进制数按位与得到
0101&0111 -> 0101
按位与&:两个位置上都是1才是1
能产生进位效果的比特位:两个对应的比特位上都是1(标红)
0 | 1 | 0 | 1 | |
+ | 0 | 1 | 1 | 1 |
包含产生进位效果的比特位的二进制数: | 0 | 1 | 0 | 1 |
相加后能产生进位效果的比特位上保留1,其余普通比特位置0
b. 其次将包含进位效果比特位的二进制数0101向左移动一位,
得到的二进制数1010就是应该进的位
以易理解的十进制视角:
5+7应该进的位是10,即得到的二进制位1010转化成十进制就是10
3. 两二进制数不进位相加的结果0010+两二进制数应该进的位1010
两二进制数相加按照上面的算法,重复如下操作:
a. 得到两二进制数按位异或(两二进制数不进位相加)的结果
b. 得到两二进制数应该进的位
3. 不进位相加的结果+应该进的位
又重复两二进制求和的算法,故而我们写成一个while循环
结束两二进制求和的条件是:两二进制数应该进的位=0
就像十进制的5+7,当5和7不进位相加的结果2+应该进的位10后,
没有要进的位了,要进的位数值是0,结束了5+7的计算,得到结果12