【算法学习】-【位运算】-【另类加法】

牛客网原题链接:另类加法

下面是题目描述:
给定两个int A和B。编写一个函数返回A+B的值,但不得使用+或其他算数运算符。

测试样例:
1,2
返回:3

1、解题思路
所谓解题思路,其实可以算作一个二进制加法的知识点。进行二进制加法,主要分为以下两步:
(1)得到两个二进制数相加后每一位上的结果
不考虑进位下,二进制数相加后每一位上的结果可分为如下几种情况:

1 + 1 = 00 + 0 = 00 + 1 = 0

那么可以发现,和位运算符异或^的结果一致,即:

1 ^ 1 = 00 ^ 0 = 00 ^ 1 = 0

这里以11+3为例:

//不考虑进位:
11的二进制:00..1011
3的二进制:00...0011
异或结果为:00..1000

所以我们可以用异或得到两个二进制数相加后每一位上的结果

(2)得到两个二进制数相加后的进位信息
将两个二进制数按位相与,在相与后的二进制数结果中,为1的一位就是需要 进位的一位;接着将相与结果左移一位,在左移后的二进制数结果中,为1的一位就是需要 “接收” 进位的一位。
这里仍以11+3为例:

//假设从第0为到第31位

11的二进制:00..1011
3的二进制:00...0011
相与结果:00...0011
//解释:第0位需向第1位进位;第1位需向第2位进位

左移结果:00..0110
//解释:第1位需接收第0位的进位;第2位需要接收第1位的进位

了解二进制加法的主要两步后,接下来的关键就是如何将这两步结合起来完成加法了:

那么其实所谓结合的过程,本质其实是对上面两步的循环,直到不需要进位为止。因为进位的本质就是每一位在不考虑进位情况下所得到的结果再加上进位信息,而所谓 “加”,正是第一步所述的过程;但 “加” 完后,还可能需要继续进位,所以需不断更新进位信息,也就是第二步所述的过程,如此就构成了循环,直到不需要进位。

下面通过两个具体例子来说明一下:

  • 11+3
11的二进制:00..1011
3的二进制:00...0011

//PS:二进制数后括号内的数为对应十进制的数值

第一步:1011 (11) ^ 0011 (3) = 1000 (8)
第二步: (1011 (11) & 0011 (3)) << 1 = 0110 (6)

第一步: 1000 (8) ^ 0110 (6) = 1110(14)
第二步: (1000 (8) & 0110 (6)) << 1 = 0000 (0)
进位信息为0,循环结束
  • 13 + 5
13的二进制:00..1101
5的二进制:00..0101

第一步:1101 (13) ^ 0101 (5) = 1000 (8)
第二步: (1101 (13) & 0101 (5)) << 1 = 1010 (10)

第一步:1000 (8) ^ 1010 (10) = 0010 (2)
第二步: (1000 (8) & 1010 (10)) << 1 = 1 0000 (16)

第一步:0010 (2) ^ 1 0000 (16) = 1 0010 (18)
第二步: (0010 (2) & 1 0000 (16)) << 1 = 0 0000 (0)
进位信息为0,循环结束

2、具体代码

    int addAB(int A, int B) 
    {
        int carry = (A & B) << 1;
        int res = A ^ B;
        while(carry != 0)
        {
            int tmp = res;
            res ^=  carry;
            carry = (carry & tmp) << 1;
        }
        
        return res;
    }

看完觉得有觉得帮助的话不妨点赞收藏鼓励一下,有疑问或看不懂的地方或有可优化的部分还恳请朋友们留个评论,多多指点,谢谢朋友们!

你可能感兴趣的:(算法学习,算法,学习,数据结构)