其他分享
首页 > 其他分享> > 位运算、数学-[371]两整数之和

位运算、数学-[371]两整数之和

作者:互联网

/*
 * @lc app=leetcode.cn id=371 lang=java
 *
 * [371] 两整数之和
 */

// @lc code=start
class Solution {
    public int getSum(int a, int b) {
        int addBit;
        /**
          看几个例子分析存在的情况:
          EG1:
                a = 0x0011 -> 3 = 1 + 2
                b = 0x0100 -> 4 = 0 + 0 + 4
            a + b = 0x0111 -> 7 = 1 + 2 + 4 [类似10进制的加法不过这里是2进制的加法,当和超过等于2时进一位,不过这个例子没有进位的情况]
            模拟下面的执行过程:
              第1次循环:
                addBit = 0x0000 -> 0
                     a = 0x0111 -> 7
                     b = addBit 
              退出因为 b = 0
              返回结果 a = 7
              这是最简单的情况了
          EG2:
                a = 0x0011 -> 3 = 1 + 2
                b = 0x0110 -> 6 = 0 + 2 + 4
            a + b = 0x1001 -> 9 = 1 + 0 + 0 + 8 [类似10进制的加法不过这里是2进制的加法,当和超过等于2时进一位]
            模拟下面的执行过程:
              第1次循环:
                addBit = 0x0100 -> 4 = 0 + 0 + 4
                     a = 0x0101 -> 5 = 1 + 0 + 4
                     b = addBit 
              第2次循环:
                addBit = 0x1000 -> 8 = 0 + 0 + 0 + 8
                     a = 0x0001 -> 1 = 1 
                     b = addBit 
              第3次循环:
                addBit = 0x0000 -> 0
                     a = 0x1001 -> 9 = 1 + 0 + 0 + 8
                     b = addBit                     
              退出因为 b = 0
              返回结果 a = 9
          EG3:
            再加上负数的情况基本就包括所有情况了
                a = 0x0000 ... 0011 -> 3  = 1 + 2  <- 补码、原码[符号位左边第一位,正数为0,负数为1]
                b = 0x1111 ... 1111                <- 补码[负数在计算机中的存储形式]
                    0x1000 ... 0000                <- 反码[补码符号位不变其它位按位取反]
                    0x1000 ... 0001 -> -1 = 1      <- 原码[反码符号位不变加1]
            a + b = 0x0000 ... 0010 -> 2 = 0 + 2   [类似10进制的加法不过这里是2进制的加法,当和超过等于2时进一位]
            模拟下面的执行过程:
              第1次循环:
                addBit = 0x0000 ..0 0110 -> 6 = 0 + 2 + 4
                     a = 0x1111 ..1 1100 -> 0x1000 ..0 0011 -> 0x1000 ..0 0100 ->  -4 = -(0 + 0 + 4)
                     [使用上面的方法:补码  ->             反码 ->             原码->  值]  
                     b = addBit                
              第2次循环:
                addBit = 0x0000 ..0 1000 -> 8 = 0 + 0 + 0 + 8
                     a = 0x1111 ..1 1010 ->
                     b = addBit 
              第3次循环:
                addBit = 0x0000 ..1 0000 -> 16 = 0 + 0 + 0 + 0 + 16
                     a = 0x1111 ..1 0010 ->
                     b = addBit      
                     ...
              [这里数字用的都是32位的整数]       
              第30次循环:
                addBit = 0x1000 ..0 0000 -> 16 = 0 + 0 + 0 + ... + 2^32
                     a = 0x1000 ..0 0010 ->
                     b = addBit    
              第31次循环:
                addBit = 0x0000 ..0 0000 -> 0
                     a = 0x0000 ..0 0010 -> 2 = 0 + 2
                     b = addBit       
              退出因为 b = 0
              返回结果 a = 2     
          由这三个例子我们可以知道基本的计算方式,这里其实对于负数可以有一些优化的情况,欢迎大家讨论分享                       

         */
        while(b != 0){
            // 记录a、b相同位,即对应位相同则记为1,且统一将整体向左移动一位
            addBit = ((a & b) << 1);
            
            // 记录a、b不同位,即对应位不同则记为1
            a = (a ^ b);

            // 根据b是否大于零判断是否继续循环
            b = addBit;
        }

        return a;
    }
}
// @lc code=end

标签:运算,..,整数,循环,0x0000,加法,371,addBit,0x1000
来源: https://blog.csdn.net/qq_36790074/article/details/120490608