371. Sum of Two Integers(Easy)
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.
题意很简单,不使用加减运算符实现两数加法。虽然是道easy难度的题,但是用的是自己不太熟悉的位运算,而且还有另外一个巧妙解法,所以也学到了很多。
常规解法:位运算
由于不能使用普通算术运算的运算符,所以只能想到接近计算机底层硬件方法的二进制计算,此外还有节约内存,提高执行效率的优点。二进制运算实际上就是逻辑运算,在c/c++中有 &(按位与)、|(按位或)、^(按位异或)、~ (按位取反),还有移位运算 << (左移) 和 >> (右移)。
考虑二进制加法,两个单二进制位相加的结果,本位与做异或运算结果相同,而进位与做与运算相同。这样我们就可以用一个数c保存a和b与运算获得的进位,令a和b相加得到本位结果d,再把c左移一位,再与d相加。。。不断重复,直到进位c为零,即运算结束。
代码如下:
class Solution {
public:
int getSum(int a, int b) {
while(b)
{
int c = a & b;
a = a ^ b;
b = c << 1;
}
return a;
}
};
巧妙解法:间接利用数组地址自动加法 time:
O(1)
虽然不能显式调用加法运算,但后台进行的数组寻址运算实际上就是在进行加法。如果能把a当做数组首地址,而b当做下标,这样a+b运算结果实际上就是a[b]的地址了。
代码如下:
class Solution {
public:
int getSum(int a, int b) {
char *c=(char*)a;
return (long)&c[b];
}
};
这种方法还有一些可以探讨的细节问题,以及由此对64位机内存机制的进一步了解。若是将上述代码中的char*换成int*,由于此时加数b每加一实际上加了sizeof(int)=4,所以得到的最终结果并不是纯粹的a+b算术运算结果。而由实验得,如果这样运行下来,结果是1+2=9,因为int占4字节,且9在一个字节的表示范围内,由此可以推出本机使用的是little endian。
然后是关于return时将地址转化为整型,若是使用int类型则会报精度丢失的错误,而至少使用了long之后就不会。因此可以推测这里的内存地址表示是在32位以上64位之下的,很有可能是40位。其实这又牵扯到另一个长久以来的疑问,为何在这些IDE里只是用了一部分地址线,而没有用满64位?也许是作为系统给分配内存的一小部分吧,也许还有很多其他复杂的内存管理问题。。。