原题如下:
LeetCode 371: Sum of Two Integers
Problem:
Calculate the sum of two integers a and b, but you are not allowed to use the operator + and -.
Example:
Given a = 1 and b = 2, return 3.
题的意思是计算两个整数的和,但是不能用加号(+)和减号(-),当然也不能用:+=、-=、++、–了,既然不能用加减来做运算,那乘除运算能求两个数的和吗,显然是不能的,除非遇到两个数相等,或者其中一个等于0等特殊情况,但是这道题要求对任意两个数字求和,那么加减乘除都不能做到这一点,自然能想到只能通过位运算来达到目的了。
首先,有关位的运算包括:按位与(&)、按位或(|)、按位异或(^)、移位。那么要如何用这些运算计算两个数的和呢。下面来看个例子。
假设有两个数
a
= 0010,
1)
a
&
2)
a
|
3)
a
^
其中与运算将对应的位均为1的位表示了出来(在这里是第2位),这就表示该位要进位,它的下一位(在这里是第三位)需要加上1。亦或将所有的对应位不相同的位表示了出来(在这里只有第一位),这就表示如果所有的位都没有进位的话,那么这个亦或的值就是答案,因为二进制的加法如果不考虑进位的话,就等价于两个二进制数相亦或。而或运算在这里的用处不大,因为加法的两个步骤:相加和进位已经分别被亦或运算和与运算实现了。那么现在来看看具体步骤:
首先,令
x=a
&
b
= 0010 表示第三位需要加一;令
要点就在于,与运算能够判断下一位是否需要加1,而亦或运算能够算出舍弃了进位的答案,那么如果循环执行这个流程,那么就能处理掉所有的进位。理解的最好办法就是再纸上多试试。
通过的代码如下:
int getSum(int a, int b) {
int shift = a & b; //找出需要进位的位
int ans = a ^ b; //得到不带进位的答案
while(shift){
shift <<= 1; //将进位标志左移一位
int pre_ans = ans; //记录之前的亦或值
ans ^= shift; //得到新的不带进位的答案
shift &= pre_ans; //找出还需要进位的位
}
return ans;
}