一、题目描述:
写一个函数,求两个整数之和,要求在函数体内不得使用 “+”、“-”、“*”、“/” 四则运算符号。
示例:
输入: a = 1, b = 1
输出: 2
提示:
a, b 均可能是负数或 0
结果不会溢出 32 位整数
二、思路分析:
这道题比较简单, 主要考的就是位运算
回顾
回顾下 计算机在处理 加法 的运算逻辑:
原码:
- 最高位为符号位, 其余位数为这个数的二进制表示 反码:
- 整数: 和原码一样
- 负数: 反码是在其原码的基础上, 除了符号位数不变,其余位取反. 补码:
- 整数: 和原码一样
- 负数: 补码是在其原码的基础上, 符号位不变, 其余各位取反, 最后+1. (即在反码的基础上+1)
剩下的就是 按位加,多出来的数字向更高位产生一个进位, 这样就完成一个二进制的加法
java 中 数字就是按补码的结果存储的, 使用补码的好处是, 减法也可以按加法的运算结果做。
思考这题
先看几个二进制的加法
| 00 | 01 | |
|---|---|---|
| 00 | 00 | 01 |
| 01 | 01 | 10 |
可以看到
- 第0位的结果: 两个数的第0位的异或
- 第1位的结果: 两个数的第1位的异或 在异或第0位的进位
设 a 二进制的第i位为 a[i], b 二进制的第i位为 b[i]
第i位的是否有进位表示为 n[i-1] 第i位的和 m[i]
则 a[i] + b[i] = n[i-1] + m[i]
进一步 a + b = n + m
其中 n 是进位和所组成的数字,m是和组成的数字
所以如果一直做转换,可以确定, 当转换的结果中 进位和全是0构成的时候,也就是说n=0的时候,m就是a+b的结果
三、AC 代码:
public class Main {
static int add(int a, int b) {
while(b != 0) {
int c = a ^ b; // 非进位和 n
b = (a & b) << 1; // 进位和 m
a = c;
// System.out.printf("%d, %d\n", a, b);
}
return a;
}
public static void main(String[] args) {
System.out.println(add(5, 3));
System.out.println(add(1, 1));
}
}
四、思考:
经过多轮测试, 发现 如果判断条件是进位和=0比判断条件非进位和=0要多一轮循环, 所以有小伙伴知道是为啥呢? 欢迎评论留言😃