LeetCode #2 Medium

Add Two Numbers

Two non-empty lists store digits in reverse order, one digit per node. Add the numbers and return the sum as a list, also in reverse order.

Constraints
  • The number of nodes in each linked list is in the range [1, 100].
  • 0 <= Node.val <= 9
  • It is guaranteed that the list represents a number that does not have leading zeros.
linked-listmathrecursion
Open on LeetCode ↗
02

Intuition

Add two numbers adds two integers stored as linked lists whose digits run in reverse order, returning the sum in the same form. The reversal is a gift rather than an obstacle — least significant digit first is exactly the order manual addition works in. So the algorithm is column addition, walked node by node: - At each position add the two digits and the carry, store sum % 10 in a new node, and keep sum / 10 as the next carry. No reversal, no conversion to integers. Converting is in fact the trap: the lists can hold up to 100 digits, which overflows every fixed-width integer type. The linked list representation exists precisely to allow arbitrarily large numbers, so the digit-wise walk is the intended approach rather than a workaround. The lists can differ in length, so the loop must continue while either list has nodes remaining, treating a missing digit as 0. Stopping when the shorter list ends silently truncates the answer. The case most often missed is a final carry. Adding [5] and [5] produces a carry after both lists are exhausted, and the answer needs an extra node. So the loop condition must also continue while the carry is non-zero, or 999 + 1 returns 000. A dummy head node removes the special case for the first node. Build onto dummy.next and return that at the end, so no branch is needed to distinguish the first append from the rest.

How to spot this pattern

To add two numbers in linked list form, digits stored least-significant-first means you can add left to right exactly as you would on paper. The dummy head removes the special case for the first node, and driving the loop on l1 or l2 or carry folds three termination cases — unequal lengths and a final carry — into one condition.

03

Approach

Try it first

Before reading on: price up what the direct approach costs here, then ask which pointers must be saved before you overwrite anything. Aim for O(max(m, n)) time and O(max(m, n)) space.

1

Use the reversed order directly

Least significant digit first is the order manual addition already uses. No reversal is needed — walk both lists forward and add column by column.

2

Never convert to an integer

The lists hold up to 100 digits, which overflows every fixed-width type. The linked list representation exists to allow numbers too large to store, so digit-wise addition is the intended method.

3

Add digits with a carry

At each position compute d1 + d2 + carry, store sum % 10 in a new node, and set carry = sum / 10. This is column addition, one node per column.

4

Continue while either list remains

The lists can differ in length, so loop while either has nodes, treating a missing digit as 0. Stopping at the shorter list truncates the answer.

5

Handle the final carry

Continue while the carry is non-zero too. Adding [5] and [5] carries after both lists end, and without this 999 + 1 returns 000.

6

Build behind a dummy head

Append onto a dummy node and return dummy.next. This removes the branch that would otherwise distinguish the first node from every later one.

7

Cost of the traversal

Each list is walked once, giving O(max(m, n)) time. The output list is the same length plus at most one carry node, so space is O(max(m, n)).

04

Solution & live demo

▶1class Solution:
▶2 def addTwoNumbers(self, l1, l2):
▶3 dummy = tail = ListNode(0)
▶4 carry = 0
▶5 while l1 or l2 or carry:
▶6 a = l1.val if l1 else 0
▶7 b = l2.val if l2 else 0
▶8 carry, digit = divmod(a + b + carry, 10)
▶9 tail.next = ListNode(digit)
▶10 tail = tail.next
▶11 l1 = l1.next if l1 else None
▶12 l2 = l2.next if l2 else None
▶13 return dummy.next
05

Common pitfalls

Dropping the final carry

✗ Wrong
while l1 or l2:
✓ Right
while l1 or l2 or carry:

Adding 5 + 5 leaves a carry after both lists are exhausted, and the answer needs one more node. Including carry in the loop condition handles it without a trailing special case.

Advancing pointers without a null check

✗ Wrong
l1 = l1.next
l2 = l2.next
✓ Right
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None

The lists can differ in length, so one runs out first and dereferencing it throws. The same guard is needed when reading the values — hence a = l1.val if l1 else 0.

Building the number then converting back

✗ Wrong
n1 = int(''.join(str(d) for d in digits1)[::-1])
return make_list(n1 + n2)
✓ Right
carry, digit = divmod(a + b + carry, 10)

Works in Python's arbitrary-precision integers, but overflows immediately in C++ or Java — and the lists can hold 100 digits. Digit-wise addition has no size limit and is what the question is testing.

06

Edge cases

Different lengths, e.g. [9,9] + [1]

Treat a missing node as 0, so the shorter list simply contributes zeros once exhausted.

Final carry, e.g. [5] + [5] = [0,1]

The loop condition includes carry, so a trailing carry creates the extra high-order node.

Both single zeros

0 + 0 = 0 with no carry; one result node holding 0 is produced.

07

Complexity

Time
O(max(m, n))
Space
O(max(m, n))
One pass over the longer list; the result has at most one extra node.