Hi👋SpeedAlgo • Deliberate Practice & Cognitive Ergonomics for Software Engineers

An interactive algorithm mastery and technical interview preparation platform published by Hi👋WebEnterprise. Built for senior and staff software engineers preparing for rigorous coding screens at top tech companies (FAANG/MAMAA).

13 Core Algorithmic Patterns & 225 Practice Problems

  • 1. Two Pointers (16 Paradigms, 43 Problems): Opposite ends, sorted pair sums, palindrome verification, trapping rain water, 3Sum, container with most water — includes the Sliding Window and Fast & Slow Pointers paradigms (contiguous subarray invariants, longest substrings, Floyd's cycle detection, linked list middle).
  • 2. Binary Search (9 Paradigms, 14 Problems): Monotonic predicate partitioning (feasible(x)), boundary search, rotated sorted arrays, square roots, minimum ship capacity, median of two sorted arrays, matrix median on value range.
  • 3. Bit Manipulation (5 Paradigms, 11 Problems): Counting set bits, XOR cancellation, bit reversal, bitmask pairing, maximum XOR with a bitwise trie.
  • 4. Math & Geometry (8 Paradigms, 14 Problems): Sieve of Eratosthenes, integer/roman conversions, modular arithmetic, geometric simulation.
  • 5. Tree/Graph Depth-First Search (15 Paradigms, 24 Problems): Path sums, lowest common ancestor, tree diameter, validating BSTs, tree DP (House Robber III, Binary Tree Cameras).
  • 6. Tree/Graph Breadth-First Search (5 Paradigms, 12 Problems): Level-order traversals, shortest path in unweighted graphs, zig-zag traversals, rotting oranges, word ladders.
  • 7. Graphs (12 Paradigms, 22 Problems): Topological sort, cycle detection, Dijkstra's algorithm, bipartite graph validation, network delay.
  • 8. Backtracking (6 Paradigms, 14 Problems): Subsets, permutations, combinations, constraint satisfaction, pruning, N-Queens, Sudoku solver.
  • 9. Dynamic Programming (13 Paradigms, 28 Problems): Memoization vs tabulation, 0/1 knapsack, unbounded knapsack, coin change, edit distance, longest common subsequence.
  • 10. Heap / Priority Queue (9 Paradigms, 11 Problems): Running medians, top-k elements, interval scheduling, IPO, k-way merges.
  • 11. Advanced Data Structures (7 Paradigms, 17 Problems): Trie (prefix tree), Union-Find (Disjoint Set Union), LRU Cache, LFU Cache, range-sum queries with updates.
  • 12. Stack (5 Paradigms, 9 Problems): Next greater element, largest rectangle in histogram, remove k digits, decode string, min stack.
  • 13. Intervals & Greedy (2 Paradigms, 6 Problems): Merge intervals, interval scheduling, meeting rooms by sweep line, jump game.

4-Stage Deliberate Practice Framework

  1. Stage 1 (Compare & Learn): Read the pattern's mental model, loop invariant and Big-O proof, compare the pattern's template with the problem's solution side by side, and use the step-by-step debugger. The solution can also be shown in C#, Java, TypeScript, C++, Go or Rust for almost every problem.
  2. Stage 2 (Active Recall): Rebuild the solution from memory in a code editor, with an invariant checklist and optional progressive hints, and check it against a judged test suite.
  3. Stage 3 (AI Interview Coach, coming soon): A mock-interview stage still in development; for now, students go straight from Stage 2 to Stage 4.
  4. Stage 4 (Solve on Your Own): Solve a new problem on your own against a 15-minute timer; your code is graded against a test suite. Python and TypeScript run in your browser and C# runs on our server (design problems grade in Python and TypeScript).

Equipped with a spaced-repetition review hub on a fixed 7-step schedule (1 day up to 90 days), a two-pane Studio workspace, and study notes.

Pricing, Access & Commercial Terms

  • Core Curriculum: 100% Free. No credit card required.
  • Coins: New accounts get 40 free coins once, the daily claim adds +20 coins once a day, and inviting a friend earns you +25 coins when they complete their first practice step. These are the only ways to earn coins.
  • AI Coach: Each AI coach question costs 1-5 coins, priced by the server according to its size.
  • BYOK (Bring Your Own Key): AI coaching is free with your own Google Gemini, OpenAI or OpenRouter API key (BYOK).
  • Extras: Coins also unlock extras for 24 hours: a Recall hint level (1 coin), a Solve solution reveal (2), a LeetCode problem card's solutions (1) and a pattern's extra canonical problems (1).
  • Payments & Refunds: Nothing on the site is sold for money: coins can only be earned, never bought. There are no subscriptions or charges, so there is nothing to refund.
  • Platform Operator: Hi👋WebEnterprise. Support & policies at hispeedalgo.com.
Skip to main content
Hi👋SpeedAlgo

Invariant-First Algorithmic Mastery

Arena
238Items
Theory Context•Bit Manipulation

Builds on Bit Tricks, which you haven’t finished yet.

P2MediumBuilt on Bit Tricks~3 min speedrun

Add Without + or - (Sum of Two Integers)

Built on
Bit TricksCombine two numbers with XOR and with AND shifted left by 1, then repeat with the carry as the new second number until it is 0.
The problem

Sum of Two Integers (LC 371)(opens leetcode.com)

You get two integers, a and b. Return their sum. The code may not use the + operator or the - operator anywhere.

The only tools left are the bitwise operators and shifts, which work on the binary digits of a number.

Example 1
Input:a = 1, b = 2
Output:3
1 is 01 and 2 is 10. No place has a 1 in both numbers, so there is no carry, and the sum without carries is 11, which is 3.

Carry Add

a, b ➔ total = a ^ b, carry = (a & b) << 1, repeat until carry is 0 ➔ signed 32-bit result
Spot it when: You must add or combine two integers without the + and - operators, or repeat an operation until a carry is gone.
Carry Add
Python
1def add_without_plus(a: int, b: int) -> int:
2 """Sum of Two Integers: add without + or -; XOR adds without carries, AND shifted left finds the carries.
3 Time: O(1), at most 32 rounds | Space: O(1)
4 """
5 # mask: the low 32 bits; sign_max: the largest signed 32-bit value
6 mask, sign_max = 0xFFFFFFFF, 0x7FFFFFFF
7 a, b = a & mask, b & mask
8 
9 # 1. Add Without Carries, Then Move The Carries:
10 # a ^ b is the sum of every bit place without carries. (a & b) << 1 holds the carries, each one place to the left.
11 # Repeat with the carries as the new b. Each round moves the carries one place left, and the mask drops them after bit 31.
12 while b:
13 total = (a ^ b) & mask
14 carry = ((a & b) << 1) & mask
15 a, b = total, carry
16 
17 # 2. Convert Back To A Signed Value:
18 # A pattern above sign_max has bit 31 set, which means a negative number in 32-bit two's complement.
19 return a if a <= sign_max else ~(a ^ mask)
Invariant: a + b equals the original sum, modulo 2 ** 32, after every round.

a ^ b is the sum of every bit place without carries, and (a & b) << 1 holds exactly the carries, each one place to the left, so set a to total, set b to carry, and repeat until b is 0. A place makes a carry only when both numbers have a 1 there, which is what a & b marks, and the carry is added to the next place, which is the << 1. Each round moves every carry at least one place left, so the carries leave the 32-bit word after at most 32 rounds. In Python, cut a, b, total and carry to 32 bits with mask, and end with a if a <= sign_max else ~(a ^ mask): a negative Python integer has no fixed width, so for -1 + 1 without the mask the loop never ends, and for -5 + -3 returning a gives 4294967288 where -8 is right.

See it run

Sum of Two Integers, step by step

round 0 · a 23 · b 41

round 1 · a 62 · b 2

round 1 · a 62 · b 2

round 2 · a 60 · b 4

round 3 · a 56 · b 8

round 4 · a 48 · b 16

round 5 · a 32 · b 32

round 6 · a 0 · b 64

round 7 · a 64 · b 0

round 7 · a 64 · b 0 · answer 64

Rows from the top: a, b, total (a ^ b) and carry ((a & b) << 1). Each column is one bit position, with the highest position on the left. The next round uses total as a and carry as b.

  • both 1 a bit place where a and b both have a 1, so it makes a carry
  • carry a carry, already moved one place to the left

Start: a = 23 and b = 41. The loop repeats while b is not 0.

total = a ^ b = 62. carry = (a & b) << 1 = 2.

Without << 1, the carry stays in its own places, and the loop would end with a | b = 63. The sum 64 needs the shift.

total = a ^ b = 60. carry = (a & b) << 1 = 4.

total = a ^ b = 56. carry = (a & b) << 1 = 8.

total = a ^ b = 48. carry = (a & b) << 1 = 16.

total = a ^ b = 32. carry = (a & b) << 1 = 32.

total = a ^ b = 0. carry = (a & b) << 1 = 64.

total = a ^ b = 64. carry = (a & b) << 1 = 0.

b = 0 after 7 rounds, so the loop ends. a = 64 is the sum of 23 and 41.

a
70
60
50
41
30
21
11
01
b
0
0
1
0
1
0
0
1
total
carry
1 / 10
Gotchas1 of 4

Gotcha 1 of 4

  1. 1
    The trap

    Gotcha 1: Using no 32-bit mask in Python

    Mistake
    a, b = a ^ b, (a & b) << 1
    Fix
    total = (a ^ b) & mask
    carry = ((a & b) << 1) & mask
    a, b = total, carry

    What happens: A Python integer has no fixed width, so a negative number behaves as if infinitely many 1 bits stood to its left. For -1 + 1, every round finds a 1 in both numbers one place higher than in the round before, so the carry moves left forever and b never becomes 0. mask keeps only the low 32 bits, so the carry leaves the word after at most 32 rounds.

    Example: Sum of Two Integers (LC 371): a = -1, b = 1
    Mistake: the loop never endsFix: returns 0
  2. 2

    Gotcha 2: Not shifting the carry one place left

    Mistake
    carry = (a & b) & mask
    Fix
    carry = ((a & b) << 1) & mask

    What happens: a & b marks the places where both numbers have a 1. Each of those places produces a carry, and the carry belongs to the next place to the left. Without << 1, the carry is added back into the same place, so the sum is too small.

    Example: Sum of Two Integers (LC 371): a = 2, b = 3
    Mistake: returns 3Fix: returns 5
  3. 3

    Gotcha 3: Returning a without converting it back to a signed value

    Mistake
    return a
    Fix
    return a if a <= sign_max else ~(a ^ mask)

    What happens: After the loop, a holds a 32-bit pattern as a number from 0 to 4294967295. Python reads bit 31 as the value 2147483648, not as a sign. A negative sum has bit 31 set, so it comes out as 2 ** 32 minus its size. a ^ mask flips all 32 bits, and ~ turns that into the negative number with the same 32 bits.

    Example: Sum of Two Integers (LC 371): a = -5, b = -3
    Mistake: returns 4294967288Fix: returns -8
  4. 4

    Gotcha 4: Running one round instead of looping until b is 0

    Mistake
    if b:
    Fix
    while b:

    What happens: One round adds the carries of the original bits, but the new carry can itself cause another carry. The loop must continue until no carry is left. For 2 + 3, round one gives total = 1 and carry = 4, and 1 and 4 still have to be combined.

    Example: Sum of Two Integers (LC 371): a = 2, b = 3
    Mistake: returns 1Fix: returns 5
Not this one if…
  • Equal values must cancel, as in Single Number (LC 136), so XOR alone is enough and there is no carry to move. See XOR Cancel
  • The numbers are digit arrays or strings, handled one decimal digit at a time, as in Multiply Strings (LC 43), not whole integers combined with bit operators. See Digit Manipulation

Deep Dive

Why XOR and AND add two numbers

Bit Tricks already taught shifts and masks. This card adds one idea: an addition splits into a sum without carries and a separate carry.

Look at one bit place. If a and b have different bits there, the sum bit is 1 and nothing carries. If both bits are 0, the sum bit is 0. If both bits are 1, the sum bit is 0 and the place sends a carry to the next place.

So a ^ b is the sum of every place without carries. a & b marks the places that send a carry. The carry belongs to the next place on the left, so the carries are (a & b) << 1.

The true sum is (a ^ b) + ((a & b) << 1). The loop repeats this with a = total and b = carry. Each round has the same sum as before, and the carry moves further left.

Example with a = 23 and b = 41, in 8 bits: 00010111 and 00101001. Round 1 gives total = 62 and carry = 2. The carries in rounds 1 to 6 are 2, 4, 8, 16, 32 and 64. After 7 rounds b is 0, and a is 64. That is 23 + 41.

Why the loop ends, and why Python needs the mask

Each round moves every carry at least one place to the left. In a 32-bit word, a carry that moves past bit 31 is cut off by & mask. So after at most 32 rounds, b is 0.

A Python integer has no fixed width. A negative number acts as if it had infinitely many 1 bits to the left. For -1 + 1, a 1 meets a 1 one place higher in every round. The carry never leaves, and the loop without a mask does not end.

mask = 0xFFFFFFFF keeps the low 32 bits. With the mask, -1 + 1 ends after 32 rounds with a = 0. I ran this and the result is 0.

Reading the 32-bit result as a signed number

After the loop, a is a pattern of 32 bits. Python reads it as a number from 0 to 4294967295. Bit 31 counts as the value 2147483648, not as a sign.

A negative sum has bit 31 set. For -5 + -3, the loop ends with a = 4294967288. The final line a if a <= sign_max else ~(a ^ mask) fixes this. a ^ mask flips all 32 bits, and ~ turns that into the negative number with the same 32 bits. The result is -8.

The cost is at most 32 rounds, and each round does a constant amount of work. The time is O(1) for a fixed width, and the space is O(1).

If the true sum does not fit in 32 signed bits, the result wraps around. For 2147483647 + 1, the function returns -2147483648, as a 32-bit machine would.

60-Second Pitch

"I split the addition into two parts. a ^ b is the sum of every bit place without carries. (a & b) << 1 is the carries, each one place to the left. I set a to the first part and b to the second, and I repeat until b is 0. Each round moves the carries at least one place left, so there are at most 32 rounds. In Python I cut every value to 32 bits with mask, because a negative integer has no fixed width. At the end, if a is above sign_max, I convert it with ~(a ^ mask). That is O(1) time and O(1) space."

Common Questions

What is the time and space complexity?

O(1) time and O(1) space for 32-bit integers. The loop runs at most 32 rounds, and each round does a constant amount of work.

Why does the loop need a mask in Python?

A Python integer has no fixed width, so a negative number acts as if it had infinitely many 1 bits on its left. The carry then never leaves. mask keeps the low 32 bits, so the carry leaves after at most 32 rounds.

How do you get the signed result at the end?

If a is above sign_max = 0x7FFFFFFF, bit 31 is set. Return ~(a ^ mask). a ^ mask flips all 32 bits, and ~ makes the negative number with the same 32 bits. For -5 + -3, this gives -8.

Why is one round not enough?

A carry can create a new carry. For 2 + 3, round 1 gives total = 1 and carry = 4. These two values still have to be combined, so the loop continues until b is 0.

How is this related to Add Binary (LC 67)?

Both add numbers bit by bit with carries. In Add Binary (LC 67), the inputs are strings, so you walk from the last character and keep one carry. In Sum of Two Integers (LC 371), the inputs are integers, and the bit operators handle all places at once.

SWE Reasoning

Spot it

  • The statement forbids the + and - operators.
  • The statement asks you to combine two integers with only bit operators.
  • A process repeats until a carry is gone, as in adding two binary strings by hand. Compare Add Binary (LC 67), where the inputs are strings.
  • Negative integers are allowed, and the language may have no fixed integer width.

The invariant, step by step

  1. Start with a and b cut to 32 bits by mask. The sum a + b is the original sum, modulo 2 ** 32.
  2. In a round, total = a ^ b is the sum of every place without carries.
  3. carry = (a & b) << 1 holds the carries. Each carry sits one place to the left of the place that made it.
  4. The new pair (total, carry) has the same sum modulo 2 ** 32 as the old pair (a, b).
  5. Each round moves every carry at least one place left. After at most 32 rounds, every carry has left the word, and b = 0.
  6. Then a is the sum as a 32-bit pattern. The last line converts it to a signed value.

Traps

  • No 32-bit mask in Python. A negative number never loses its infinite 1 bits. For -1 + 1 the loop does not end.
  • No << 1 on the carry. The carry is added back to the same place that made it. For 2 + 3, the function returns 3 instead of 5.
  • return a without the sign conversion. For -5 + -3, the function returns 4294967288 instead of -8.
  • if b: instead of while b:. One round is not enough, because a carry can make another carry. For 2 + 3, one round leaves total = 1 and carry = 4, and the function returns 1.

Practice

Canonical LeetCode:Sum of Two Integers (LC 371)Add Binary (LC 67)
Theory Context•Bit Manipulation

Builds on Bit Tricks, which you haven’t finished yet.

P2MediumBuilt on Bit Tricks~3 min speedrun

Add Without + or - (Sum of Two Integers)

Built on
Bit TricksCombine two numbers with XOR and with AND shifted left by 1, then repeat with the carry as the new second number until it is 0.
The problem

Sum of Two Integers (LC 371)(opens leetcode.com)

You get two integers, a and b. Return their sum. The code may not use the + operator or the - operator anywhere.

The only tools left are the bitwise operators and shifts, which work on the binary digits of a number.

Example 1
Input:a = 1, b = 2
Output:3
1 is 01 and 2 is 10. No place has a 1 in both numbers, so there is no carry, and the sum without carries is 11, which is 3.

Carry Add

a, b ➔ total = a ^ b, carry = (a & b) << 1, repeat until carry is 0 ➔ signed 32-bit result
Spot it when: You must add or combine two integers without the + and - operators, or repeat an operation until a carry is gone.
Carry Add
Python
1def add_without_plus(a: int, b: int) -> int:
2 """Sum of Two Integers: add without + or -; XOR adds without carries, AND shifted left finds the carries.
3 Time: O(1), at most 32 rounds | Space: O(1)
4 """
5 # mask: the low 32 bits; sign_max: the largest signed 32-bit value
6 mask, sign_max = 0xFFFFFFFF, 0x7FFFFFFF
7 a, b = a & mask, b & mask
8 
9 # 1. Add Without Carries, Then Move The Carries:
10 # a ^ b is the sum of every bit place without carries. (a & b) << 1 holds the carries, each one place to the left.
11 # Repeat with the carries as the new b. Each round moves the carries one place left, and the mask drops them after bit 31.
12 while b:
13 total = (a ^ b) & mask
14 carry = ((a & b) << 1) & mask
15 a, b = total, carry
16 
17 # 2. Convert Back To A Signed Value:
18 # A pattern above sign_max has bit 31 set, which means a negative number in 32-bit two's complement.
19 return a if a <= sign_max else ~(a ^ mask)
Invariant: a + b equals the original sum, modulo 2 ** 32, after every round.

a ^ b is the sum of every bit place without carries, and (a & b) << 1 holds exactly the carries, each one place to the left, so set a to total, set b to carry, and repeat until b is 0. A place makes a carry only when both numbers have a 1 there, which is what a & b marks, and the carry is added to the next place, which is the << 1. Each round moves every carry at least one place left, so the carries leave the 32-bit word after at most 32 rounds. In Python, cut a, b, total and carry to 32 bits with mask, and end with a if a <= sign_max else ~(a ^ mask): a negative Python integer has no fixed width, so for -1 + 1 without the mask the loop never ends, and for -5 + -3 returning a gives 4294967288 where -8 is right.

See it run

Sum of Two Integers, step by step

round 0 · a 23 · b 41

round 1 · a 62 · b 2

round 1 · a 62 · b 2

round 2 · a 60 · b 4

round 3 · a 56 · b 8

round 4 · a 48 · b 16

round 5 · a 32 · b 32

round 6 · a 0 · b 64

round 7 · a 64 · b 0

round 7 · a 64 · b 0 · answer 64

Rows from the top: a, b, total (a ^ b) and carry ((a & b) << 1). Each column is one bit position, with the highest position on the left. The next round uses total as a and carry as b.

  • both 1 a bit place where a and b both have a 1, so it makes a carry
  • carry a carry, already moved one place to the left

Start: a = 23 and b = 41. The loop repeats while b is not 0.

total = a ^ b = 62. carry = (a & b) << 1 = 2.

Without << 1, the carry stays in its own places, and the loop would end with a | b = 63. The sum 64 needs the shift.

total = a ^ b = 60. carry = (a & b) << 1 = 4.

total = a ^ b = 56. carry = (a & b) << 1 = 8.

total = a ^ b = 48. carry = (a & b) << 1 = 16.

total = a ^ b = 32. carry = (a & b) << 1 = 32.

total = a ^ b = 0. carry = (a & b) << 1 = 64.

total = a ^ b = 64. carry = (a & b) << 1 = 0.

b = 0 after 7 rounds, so the loop ends. a = 64 is the sum of 23 and 41.

a
70
60
50
41
30
21
11
01
b
0
0
1
0
1
0
0
1
total
carry
1 / 10
Gotchas1 of 4

Gotcha 1 of 4

  1. 1
    The trap

    Gotcha 1: Using no 32-bit mask in Python

    Mistake
    a, b = a ^ b, (a & b) << 1
    Fix
    total = (a ^ b) & mask
    carry = ((a & b) << 1) & mask
    a, b = total, carry

    What happens: A Python integer has no fixed width, so a negative number behaves as if infinitely many 1 bits stood to its left. For -1 + 1, every round finds a 1 in both numbers one place higher than in the round before, so the carry moves left forever and b never becomes 0. mask keeps only the low 32 bits, so the carry leaves the word after at most 32 rounds.

    Example: Sum of Two Integers (LC 371): a = -1, b = 1
    Mistake: the loop never endsFix: returns 0
  2. 2

    Gotcha 2: Not shifting the carry one place left

    Mistake
    carry = (a & b) & mask
    Fix
    carry = ((a & b) << 1) & mask

    What happens: a & b marks the places where both numbers have a 1. Each of those places produces a carry, and the carry belongs to the next place to the left. Without << 1, the carry is added back into the same place, so the sum is too small.

    Example: Sum of Two Integers (LC 371): a = 2, b = 3
    Mistake: returns 3Fix: returns 5
  3. 3

    Gotcha 3: Returning a without converting it back to a signed value

    Mistake
    return a
    Fix
    return a if a <= sign_max else ~(a ^ mask)

    What happens: After the loop, a holds a 32-bit pattern as a number from 0 to 4294967295. Python reads bit 31 as the value 2147483648, not as a sign. A negative sum has bit 31 set, so it comes out as 2 ** 32 minus its size. a ^ mask flips all 32 bits, and ~ turns that into the negative number with the same 32 bits.

    Example: Sum of Two Integers (LC 371): a = -5, b = -3
    Mistake: returns 4294967288Fix: returns -8
  4. 4

    Gotcha 4: Running one round instead of looping until b is 0

    Mistake
    if b:
    Fix
    while b:

    What happens: One round adds the carries of the original bits, but the new carry can itself cause another carry. The loop must continue until no carry is left. For 2 + 3, round one gives total = 1 and carry = 4, and 1 and 4 still have to be combined.

    Example: Sum of Two Integers (LC 371): a = 2, b = 3
    Mistake: returns 1Fix: returns 5
Not this one if…
  • Equal values must cancel, as in Single Number (LC 136), so XOR alone is enough and there is no carry to move. See XOR Cancel
  • The numbers are digit arrays or strings, handled one decimal digit at a time, as in Multiply Strings (LC 43), not whole integers combined with bit operators. See Digit Manipulation

Deep Dive

Why XOR and AND add two numbers

Bit Tricks already taught shifts and masks. This card adds one idea: an addition splits into a sum without carries and a separate carry.

Look at one bit place. If a and b have different bits there, the sum bit is 1 and nothing carries. If both bits are 0, the sum bit is 0. If both bits are 1, the sum bit is 0 and the place sends a carry to the next place.

So a ^ b is the sum of every place without carries. a & b marks the places that send a carry. The carry belongs to the next place on the left, so the carries are (a & b) << 1.

The true sum is (a ^ b) + ((a & b) << 1). The loop repeats this with a = total and b = carry. Each round has the same sum as before, and the carry moves further left.

Example with a = 23 and b = 41, in 8 bits: 00010111 and 00101001. Round 1 gives total = 62 and carry = 2. The carries in rounds 1 to 6 are 2, 4, 8, 16, 32 and 64. After 7 rounds b is 0, and a is 64. That is 23 + 41.

Why the loop ends, and why Python needs the mask

Each round moves every carry at least one place to the left. In a 32-bit word, a carry that moves past bit 31 is cut off by & mask. So after at most 32 rounds, b is 0.

A Python integer has no fixed width. A negative number acts as if it had infinitely many 1 bits to the left. For -1 + 1, a 1 meets a 1 one place higher in every round. The carry never leaves, and the loop without a mask does not end.

mask = 0xFFFFFFFF keeps the low 32 bits. With the mask, -1 + 1 ends after 32 rounds with a = 0. I ran this and the result is 0.

Reading the 32-bit result as a signed number

After the loop, a is a pattern of 32 bits. Python reads it as a number from 0 to 4294967295. Bit 31 counts as the value 2147483648, not as a sign.

A negative sum has bit 31 set. For -5 + -3, the loop ends with a = 4294967288. The final line a if a <= sign_max else ~(a ^ mask) fixes this. a ^ mask flips all 32 bits, and ~ turns that into the negative number with the same 32 bits. The result is -8.

The cost is at most 32 rounds, and each round does a constant amount of work. The time is O(1) for a fixed width, and the space is O(1).

If the true sum does not fit in 32 signed bits, the result wraps around. For 2147483647 + 1, the function returns -2147483648, as a 32-bit machine would.

60-Second Pitch

"I split the addition into two parts. a ^ b is the sum of every bit place without carries. (a & b) << 1 is the carries, each one place to the left. I set a to the first part and b to the second, and I repeat until b is 0. Each round moves the carries at least one place left, so there are at most 32 rounds. In Python I cut every value to 32 bits with mask, because a negative integer has no fixed width. At the end, if a is above sign_max, I convert it with ~(a ^ mask). That is O(1) time and O(1) space."

Common Questions

What is the time and space complexity?

O(1) time and O(1) space for 32-bit integers. The loop runs at most 32 rounds, and each round does a constant amount of work.

Why does the loop need a mask in Python?

A Python integer has no fixed width, so a negative number acts as if it had infinitely many 1 bits on its left. The carry then never leaves. mask keeps the low 32 bits, so the carry leaves after at most 32 rounds.

How do you get the signed result at the end?

If a is above sign_max = 0x7FFFFFFF, bit 31 is set. Return ~(a ^ mask). a ^ mask flips all 32 bits, and ~ makes the negative number with the same 32 bits. For -5 + -3, this gives -8.

Why is one round not enough?

A carry can create a new carry. For 2 + 3, round 1 gives total = 1 and carry = 4. These two values still have to be combined, so the loop continues until b is 0.

How is this related to Add Binary (LC 67)?

Both add numbers bit by bit with carries. In Add Binary (LC 67), the inputs are strings, so you walk from the last character and keep one carry. In Sum of Two Integers (LC 371), the inputs are integers, and the bit operators handle all places at once.

SWE Reasoning

Spot it

  • The statement forbids the + and - operators.
  • The statement asks you to combine two integers with only bit operators.
  • A process repeats until a carry is gone, as in adding two binary strings by hand. Compare Add Binary (LC 67), where the inputs are strings.
  • Negative integers are allowed, and the language may have no fixed integer width.

The invariant, step by step

  1. Start with a and b cut to 32 bits by mask. The sum a + b is the original sum, modulo 2 ** 32.
  2. In a round, total = a ^ b is the sum of every place without carries.
  3. carry = (a & b) << 1 holds the carries. Each carry sits one place to the left of the place that made it.
  4. The new pair (total, carry) has the same sum modulo 2 ** 32 as the old pair (a, b).
  5. Each round moves every carry at least one place left. After at most 32 rounds, every carry has left the word, and b = 0.
  6. Then a is the sum as a 32-bit pattern. The last line converts it to a signed value.

Traps

  • No 32-bit mask in Python. A negative number never loses its infinite 1 bits. For -1 + 1 the loop does not end.
  • No << 1 on the carry. The carry is added back to the same place that made it. For 2 + 3, the function returns 3 instead of 5.
  • return a without the sign conversion. For -5 + -3, the function returns 4294967288 instead of -8.
  • if b: instead of while b:. One round is not enough, because a carry can make another carry. For 2 + 3, one round leaves total = 1 and carry = 4, and the function returns 1.

Practice

Canonical LeetCode:Sum of Two Integers (LC 371)Add Binary (LC 67)
© 2026 Hi👋WebEnterprise. All rights reserved.
Sitemap•llms.txt•