剑指 Offer 65. 不用加减乘除做加法https://leetcode.cn/problems/bu-yong-jia-jian-cheng-chu-zuo-jia-fa-lcof/
题目:
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号
输入: a = 1, b = 1 输出: 2
是一道需要我死记硬背的题目了
每次遇到 位运算 的题目,我就无能为力,二进制杀我!!!!
这里我们先来回顾一下二进制的位运算:
与运算: &
0 & 0 = 0
0 & 1 = 0
1 & 0 = 0
1 & 1 = 1
或运算: |
0 & 0 = 0
0 & 1 = 1
1 & 0 = 1
1 & 1 = 1
异或运算: ^
0 ^ 0 = 0
0 ^ 1 = 1
1 ^ 0 = 1
1 ^ 1 = 0
左位移运算符: <<
将二进制码整体左移指定位数,左移后空出来的位用“0”填充
右位移运算符:>>
>>
把操作数的二进制码右位移指定位数,左边空出来的位以原来的符号位填充。原来是负数就填充1,原来是正数就填充0无符号右位移运算符:>>>
>>>
把操作数的二进制码右位移指定位数,左边空出来的位以0
填充。无符号位右移结果总是一个正数。
我们注意看 异或运算
我们看到如果不考虑进位,那么a+b的结果其实就是a^b的结果
1100
1111
————
0011
我们注意看 与运算
就是只有
1+1
有进位,其他的都没进位。所以判断有没有进位只需要判断a&b
是否等于1
即可1100
1111
————
1100 向左移移一位: 11000
我们可以看见 第一二 步骤相加的结果 就是 1100+1111 的结果 = 11011
但是题目明确说到,不能使用 + - * % 加减乘除
借用一下大神的图:@陆艰步走
我们发现发现,a+b
通过^
和&
运算之后又再执行相加操作,所以我们首先想到的是递归
从上图,你大概可以看出,这个就是在不断重复第一,第二的步骤,那么退出条件是什么?
其实我们可以设想一个最坏的情况,那就是,这个循环到了一个情况,会在一直循环的情况,结果依然不变?
无疑,那就是,进位的结果为0的情况,所以,其实在不考虑溢位的情况下,其实最多最多就是循环32次就行,
那么咱们上代码:
递归法
// 递归法
class Solution {
public int add(int a, int b) {
while(b != 0){
int c = a^b;
int d = (a&b)<<1;
a = c;
b = d;
}
return a;
}
}
非递归法
class Solution {
public int add(int a, int b) {
if(b == 0) return a;
int c = a^b;
int d = (a&b)<<1;
return add(c,d);
}
}