[LeetCode] 371. Sum of Two Integers

Given two integers a and b, return the sum of the two integers without using the operators + and -.

Example 1:

Input: a = 1, b = 2
Output: 3

Example 2:

Input: a = 2, b = 3
Output: 5

Constraints:

  • -1000 <= a, b <= 1000

两整数之和。

给你两个整数 a 和 b ,不使用 运算符 + 和 - ​​​​​​​,计算并返回两整数之和。

思路是位运算,但是非常难想,需要复习。我是参考了这个帖子这个帖子才想通了的。

ab低位进位
0 0 0 0
1 0 1 0
0 1 1 0
1 1 0 1

首先注意到,任意两个数字a和b相加的时候,他们的低位和高位的结果是什么?如上图所示,你会发现一个规律,低位的结果是a^b(两数相同为0,两数不同为1),而进位的结果是a&b(两数相同为0,两数不同为1)。那么做法就是设两个变量lowercarry来分别记录两者相加的低位高位。lower = a ^ b, carry = a & b,一轮结束后,如果carry = 0说明没有进位,则可以直接退出while循环并且返回lower;如果carry = 1则说明有进位,此时需要把低位赋予a,把carry左移一位的结果赋予b再做运算。例子,5 + 7的话,其实是101 + 111

a ^ b如下 = 相加各个位置上的值但是不计算进位

1 0 1

1 1 1

----

0 1 0

a & b如下 = 计算各个位置上的进位值

1 0 1

1 1 1

----

1 0 1,再向左移动一位,101 << 1 = 1010

重复上述两步,

a ^ b = 010 ^ 1010 = 0010 ^ 1010 = 1000

a & b = 010 & 1010 = 0010 & 1010 = 0010,左移一位,0010 << 1 = 0100

重复上述两步,

a ^ b = 1000 ^ 0100 = 1100

a & b = 1000 & 0100 = 0000,因为这里进位为0,可以跳出循环了,结果就是1100

时间O(1)

空间O(1)

JavaScript实现

复制代码
 1 /**
 2  * @param {number} a
 3  * @param {number} b
 4  * @return {number}
 5  */
 6 var getSum = function(a, b) {
 7     if (a === 0) {
 8         return b;
 9     }
10     if (b === 0) {
11         return a;
12     }
13     while (b !== 0) {
14         let carry = a & b;
15         a = a ^ b;
16         b = carry << 1;
17     }
18     return a;
19 };
复制代码

 

Java实现

复制代码
 1 class Solution {
 2     public int getSum(int a, int b) {
 3         if (a == 0) {
 4             return b;
 5         }
 6         if (b == 0) {
 7             return a;
 8         }
 9         int lower;
10         int carrier;
11         while (true) {
12             lower = a ^ b; // 计算低位
13             carrier = a & b; // 计算进位
14             if (carrier == 0) {
15                 break;
16             }
17             a = lower;
18             b = carrier << 1;
19         }
20         return lower;
21     }
22 }
复制代码

 

二刷我参考了一个更好理解的代码。对于一个 Integer,他只有32位,所以我们只需要计算这 32 位上应该分别是什么数字即可。那么我们遍历 32 次,每次我们分别把数字 a 和数字 b 在这一位上的 digit 取出来,设为 u1 和 u2。这里我们对每一位做加法,用 carry 存储进位。那么,

  • 如果 u1 和 u2 都是 1,res 在这一位的二进制表达就是 0 (1 + 1 = 0),但是记住我们要把之前的进位 carry 带上,同时此时 carry = 1,因为当前位是有进位的
  • 如果 u1 和 u2 其中只有一个是 1,那么 res 在这一位上的二进制表达是前一位的进位情况。而这里的抑或 XOR 操作,巧妙地执行了这个任务。因为 XOR 操作下,两者相同为 0,不同为 1
  • 如果 u1 和 u2 都是 0,此时当前位是什么取决于前一位的进位情况

Java实现

复制代码
 1 class Solution {
 2     public int getSum(int a, int b) {
 3         int res = 0;
 4         int carry = 0;
 5         for (int i = 0; i < 32; i++) {
 6             int u1 = (a >> i) & 1;
 7             int u2 = (b >> i) & 1;
 8             if (u1 == 1 && u2 == 1) {
 9                 res |= (carry << i);
10                 carry = 1;
11             } else if (u1 == 1 || u2 == 1) {
12                 res |= ((1 ^ carry) << i);
13             } else {
14                 res |= (carry << i);
15                 carry = 0;
16             }
17         }
18         return res;
19     }
20 }
复制代码

 

LeetCode 题目总结

posted @   CNoodle  阅读(158)  评论(0编辑  收藏  举报
点击右上角即可分享
微信分享提示