371. Sum of Two Integers

The Problem

Link to original problem on Leetcode.

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

Examples

Example 1:

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

Example 2:

Input: a = 2, b = 3
Output: 5
Constraints
  • -1000 <= a, b <= 1000

My Solution

To add two numbers without + or -, we'll use binary. I mainly write JavaScript for web application, which means I use bitwise operations approximately never. But hey, that's leetcode!

Anyway, bitwise operations include:

So, how can we use this information to find the sum of integers?

First, let's think of an example pair of integers: 7 and 4. In binary, they can be represented as 0111 and 0100. Adding in binary works the same as adding in base ten:

  0111 => 7
+ 0100 => 4
------
  1011 => 11

From this simple example, we can see that for each digit, a 0 and a 1 will have a 1 in the result. Two 0's result in a 0, and two 1's result in a 0 and a carried 1 to the next place.

This means two things:

We can figure out where we'll need carried digits with AND. Then to get them into the right position, we'll have to shift them left. In our example:

  0111
& 0100
------
  0100 <= the 4's digit is where a 1 will need to carry over

  0100
<<   1
------
  1000 <= Shifting left by one bit, the carried bit is in the right place

Now that we know were our carried digits will go, we can go ahead and find the the digits that should come out to 1 with XOR.

  0111
^ 0100
------
  0011

We're close, but remember, we can't use + here! We can't say 1000 + 0011 = 1011 and be done with it. Instead, we'll change the values of our original variables with our new results.

First, find the digits to carry:

  0011 => 7 ^ 4
& 1000 => (7 & 4) << 1
------
  0000 <= nothing left to carry over!

Now we find the digits that will equal 1 using XOR:

  0011 => 7 ^ 4
^ 1000 => (7 & 4) << 1
------
  1011 => 11, our answer!

Time to translate this to code. We're going to want a variable to keep track of digits to carry, and a loop to continue executing these steps until we've got our answer. Note that in our example, our carried over digits ended up at 0—we can use that as a conditional for our loop to know when to stop.

In our function, we're passed to integers, a and b. We can mutate them to keep track of our intermediate steps. Let's store the XOR'ed values (and ultimately, our answer) in a, and our carried over values in b. We need to have a third variable to store the carried values, because we can't find out what they should be from a and b if we've already mutated a to equal a ^ b.

const getSum = (a, b) => {
let carry;
// When there are no digits left to carry, b will
// equal 0 and a will equal our answer.
while (b !== 0) {
// Store the digits we'll need to carry over.
carry = (a & b);
// Find the digits that will equal 1 in binary,
// then mutate a to equal the result.
a = a ^ b;
// Mutate b to equal the carried digits, shifted
// once to the left.
b = carry << 1;
}
return a
};

You can also write this code more pithily with recursion like so:

const getSum = (a, b) => {
return b ? getSum(a ^ b, (a & b) << 1) : a;
};