371. Sum of Two Integers

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.

要求完成int加法,完全不能使用算数运算符,那么直接的想法肯定是二进制里可以用的与,或,异或,移位。这里有个问题就是负数怎么办,这里记住,负数在二进制表示时是以他的补码形式,这里有个特别好的例子中途插进来说一下:

void main()
{
char *p;
*p=-130;
printf("%d",*p);
}

问输出结果是什么,如果你说是-130那么你就错了,因为当char存储-130的时候存的补码信息,而且char只有8位,所以存的是补码的低8位。-130补码的低8位是01111110,所以打印出来是126。
上面这个例子纯粹是我觉得很有意思的例子,体会下补码的存在,据说这也是华为的面试题,感觉考察的很细致。
所以在一开始想的解法里,逐位读取a和b的每一位二进制读数,不停的记录result和进位情况,代码如下:

int getSum(int a, int b) {
    if (a == 0 || b == 0) return a | b;
    int factor = 1;
    int carry = 0;
    int result = 0;
    while (a / factor > 0 || b / factor > 0) {
        int ar = a / factor % 2;
        int br = b / factor % 2;
        if (ar ^ br == 1 && carry == 0) result |= factor;
        if (ar | br == 0 && carry == 1) {
            result |= factor;
            carry = 0;
        }
        if (ar & br == 1) {
            if (carry == 0) carry = 1;
            else result |= factor;
        }
        factor = factor * 2;
    }
    return result;
}

这个算法是错的,因为他只对正数有效,对于负数,记住,是不能通过除和取余来逐步获取原始的二进制信息的,因为负数除以2变成另一个负数,补码表示上并不仅仅是移位这么简单。所以这种策略本质上无法处理负数。
这题其实要求我们整体处理,也没有必要那么笨的逐位判断,其实这里面的加法就是,如果1,0或者0,1就直接是1,如果是1,1有进位,所以我们直接异或得出一个没有进位的结果,然后做位与,得到进位的位置,然后把这些位置左移一位就是要加1的地方,然后循环调用加法就行。

class Solution {
public:
    int getSum(int a, int b) {
        if (b == 0) return a;
        int sum = a ^ b;
        int carry = (a & b) << 1;
        return getSum(sum, carry);
    }
};

或者直接写为:

class Solution {
public:
    int getSum(int a, int b) {
        return b == 0 ? a : getSum(a ^ b, (a & b) << 1);
    }
};

为什么这个递归一定会有限次结束了?最简单的证明就是,我们每次得到的b一定比上一次的b中的1更少,因为b是做与运算来的呀,而且每次都在左移,所以一定最后为0。
或者不用递归,写成迭代也是一回事:

class Solution {
public:
    int getSum(int a, int b) {
        while (b) {
            int carry = (a & b) << 1;
            a = a ^ b;
            b = carry;
        }
        return a;
    }
};
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值