Learn/DSA Patterns
DSA PatternsLinked Listsmedium9 min read

Add Two Numbers as a Linked List

Two linked lists store digits of large integers (one digit per node). Add them just like grade-school column addition — carry included — using a dummy head and a carry variable. Handle different lengths and a final carry cleanly.

#linked-list#addition#carry#dummy-head#math#beginner#interview
Table of contents

Before we start

This problem sounds like arithmetic homework, but it teaches one of the most reusable linked list tricks: the dummy head node that makes result-list construction uniform from the very first digit. It also reinforces carry propagation — a concept that appears in binary addition, multiply strings, and big-number arithmetic problems. By the end you will be able to:

  • Build a result linked list digit by digit using a dummy head.
  • Handle carries correctly including the carry-out after the last digit.
  • Adapt the solution for digits stored in forward order (LC #445) using a stack.

Picture this first (no code yet)

A real-life story

You are adding two numbers by hand, column by column from right to left. You write the units digit, carry the tens digit to the next column, write the tens result (including carry from units), carry the hundreds, and so on. If one number has fewer digits, you treat missing columns as 0. If a carry remains after the final column, you write an extra leading digit.

The linked lists already start at the units place (the head is the least-significant digit), so you can add from the head forward — left-to-right in the list, right-to-left in the number — without reversing anything. It is column addition, digitised.


The actual problem

Add Two Numbers (LC #2):

Two non-empty linked lists represent two non-negative integers where digits are stored in reverse order (head = least-significant digit). Add them and return the sum as a linked list in the same format.

l1 = 2 → 4 → 3 represents 342.
l2 = 5 → 6 → 4 represents 465.
Sum = 807, returned as 7 → 0 → 8.

Constraints: no leading zeros (except the number 0 itself); digits 0–9; up to 100 nodes each.


First, the slow way (so you feel the pain)

Convert both lists to Python integers (traverse, build digit string, int()), add them, convert the sum back to a new linked list. This works for small numbers, but Python integers can hold arbitrarily large values while linked list problems in Java or C++ overflow 64-bit integers. The intended solution works digit by digit regardless of number length — no integer conversion required.


The turning point

Pause & think

You process each column (each pair of nodes) and get a sum that might be ≥ 10. What two things do you need to record per column?

(1) The digit to write: sum % 10.
(2) The carry to pass to the next column: sum // 10.

After both lists are exhausted, what happens if carry is still 1? You must add one more node with value 1. When does this happen? When the final digit sum is ≥ 10, e.g., adding 5 → 5 (representing 55 + 55 = 110, result 0 → 1 → 1).


The one idea to remember

The entire pattern in one sentence

Use a dummy head to avoid special-casing the first result node, loop while either list has digits or carry is nonzero, append (sum % 10) each iteration, and pass (sum // 10) as the carry to the next iteration.


The code

def addTwoNumbers(l1, l2):
    dummy = ListNode(0)   # sentinel: avoids special-casing head
    cur   = dummy
    carry = 0

    while l1 or l2 or carry:
        val1  = l1.val if l1 else 0     # treat exhausted list as 0
        val2  = l2.val if l2 else 0
        total = val1 + val2 + carry

        carry     = total // 10          # carry to next column
        cur.next  = ListNode(total % 10) # write this column's digit
        cur       = cur.next             # advance result pointer

        if l1: l1 = l1.next             # advance input pointers
        if l2: l2 = l2.next

    return dummy.next    # skip the sentinel, return real head

Line-by-line narration:

  1. dummy = ListNode(0) — a throwaway node. Its only purpose: give cur a valid next to write to from the very first iteration, so we never need "if this is the first node, set head; else append."
  2. cur = dummy — cur tracks the tail of the result list.
  3. carry = 0 — starts at zero; accumulates whenever a column sums ≥ 10.
  4. while l1 or l2 or carry: — keep going as long as there are digits left or a carry remains. The or carry is the crucial clause that handles the extra leading digit.
  5. val1 = l1.val if l1 else 0 — safe: if l1 is exhausted, treat it as 0.
  6. total = val1 + val2 + carry — column sum including carry-in.
  7. carry = total // 10 — carry-out: 0 if total < 10, else 1 (sum of two single digits + carry is at most 9+9+1=19, so carry ≤ 1 always).
  8. cur.next = ListNode(total % 10) — result digit is the units part.
  9. cur = cur.next — advance tail.
  10. if l1: l1 = l1.next — only advance if not exhausted (safe guard).
  11. return dummy.next — dummy itself has value 0 and is not part of the result.

Watch it happen, frame by frame

l1: 2 → 4 → 3 (342) | l2: 5 → 6 → 4 (465) | Expected: 7 → 0 → 8 (807)

carry=0, cur=dummy

Iter 1 (units column):
  val1=2, val2=5, total=7, carry=0
  Append node(7). dummy→7
  l1=43, l2=64. cur=node(7)

Iter 2 (tens column):
  val1=4, val2=6, total=10, carry=1
  Append node(0). dummy→7→0
  l1=3, l2=4. cur=node(0)

Iter 3 (hundreds column):
  val1=3, val2=4, total=7+1(carry)=8, carry=0
  Append node(8). dummy→7→0→8
  l1=None, l2=None. cur=node(8)

Iter 4 check: l1=None, l2=None, carry=0 → exit loop.

return dummy.next = node(7) → 708

Edge case: carry after last digits

l1: 9 → 9 (99) | l2: 1 (1) | Expected: 0 → 0 → 1 (100)

carry=0

Iter 1: val1=9, val2=1, total=10, carry=1. Append 0. l1=9, l2=None.
Iter 2: val1=9, val2=0, total=9+1=10, carry=1. Append 0. l1=None, l2=None.
Iter 3: l1=None, l2=None, carry=1. val1=0, val2=0, total=1, carry=0. Append 1.
Iter 4: all None, carry=0 → exit.

Result: 0→0→1  ✅  (represents 100)

The or carry in the loop condition is exactly what catches this final node.


Variant: digits stored in forward order (LC #445)

Add Two Numbers II (LC #445): same problem but l1 = 3 → 4 → 2 represents 342 (head = most significant digit). You cannot add head-to-head because the carries flow from right to left but the list runs left-to-right.

Strategy — stack:

def addTwoNumbersII(l1, l2):
    s1, s2 = [], []
    while l1: s1.append(l1.val); l1 = l1.next
    while l2: s2.append(l2.val); l2 = l2.next

    carry = 0
    head  = None
    while s1 or s2 or carry:
        val1  = s1.pop() if s1 else 0
        val2  = s2.pop() if s2 else 0
        total = val1 + val2 + carry
        carry = total // 10
        node  = ListNode(total % 10)
        node.next = head    # prepend to result (result builds right-to-left)
        head      = node

    return head

Key difference: we pop from stacks (so we process least-significant digits first, just like LC #2), and we prepend each new node to build the result in forward order.

Why not reverse the lists? We could reverse both inputs, run the LC #2 solution, then reverse the result — three O(n) passes. The stack approach also does three O(n) passes but keeps it as one function and avoids mutating the input lists.


Common traps

Watch out for these

  • Forgetting the final carry. The loop condition must include or carry. Without it, adding 9 → 9 + 1 gives 0 → 0 instead of 0 → 0 → 1.
  • Advancing an exhausted pointer. Always guard with if l1: l1 = l1.next. Calling l1.next on a None pointer crashes immediately.
  • Using dummy.next as the return vs dummy. The dummy node is a sentinel with value 0 that is not part of the sum. Return dummy.next — the first real result digit.
  • Carry value exceeding 1. The maximum column sum is 9 + 9 + 1 (carry-in) = 19, so carry-out is always 0 or 1. You do not need to handle carry ≥ 2. Knowing this bound lets you assert carry in (0, 1) if you want defensive code.
  • For LC #445, building the result backwards. When processing from the stacks (least-significant first), each new node must be prepended (node.next = head; head = node), not appended. Appending would reverse the result.

Remember this forever

Add Two Numbers (reversed order)

dummy = ListNode(0); cur = dummy; carry = 0
while l1 or l2 or carry:
    v1 = l1.val if l1 else 0
    v2 = l2.val if l2 else 0
    s  = v1 + v2 + carry
    carry, cur.next = s // 10, ListNode(s % 10)
    cur = cur.next
    if l1: l1 = l1.next
    if l2: l2 = l2.next
return dummy.next

Trap: or carry in the while condition — handles final carry node. Guard if l1 before advancing.


Check yourself

Why is the dummy head useful here? What would code look like without it?

Without a dummy head, you need a separate "first node" branch: check if head has been set yet; if not, create it and set head = cur = new_node; if yes, set cur.next = new_node; cur = cur.next. That conditional on every iteration is noisy. With a dummy head, cur.next is always a valid append target from the first iteration — the sentinel node absorbs the special-case logic. You simply append every time and return dummy.next at the end.

What is the maximum number of nodes in the result, relative to the lengths of l1 and l2?

Let m = len(l1) and n = len(l2). The result has at most max(m, n) + 1 nodes. The +1 accounts for a carry-out beyond the longest input's most-significant digit (e.g., 9 → 9 + 1 → 3-node result from 2-node and 1-node inputs). The result can never be longer than max(m, n) + 1 because the column sum is at most 9+9+1=19, carry ≤ 1 always, and a single final carry adds exactly one node.


Practice problems

ProblemDifficultyWhat to noticeLink
Add Two NumbersMediumdummy head; or carry in while conditionLC #2
Add Two Numbers IIMediumStack to reverse digit order; prepend result nodesLC #445
Add BinaryEasySame column-addition logic, base 2LC #67
Multiply StringsMediumAdd rows like long multiplication; carry across columnsLC #43

Next up: Clone a List with Random Pointers — where each node also has a random pointer to any node in the list (or None), requiring you to deep-copy both the next chain and the random links without confusing original and cloned nodes.