Linked Lists · Linked List Fundamentals

Linked List Arithmetic

Simulating grade-school addition digit by digit down two lists in parallel, carrying the overflow forward and building the result as a new list.

  • 6 min read
  • 9 practice questions
  • 2 graded problems
On this page
  1. Description
  2. The approach
  3. A second flavor: forward-order digits need a stack
  4. Where you'll see it
  5. Which tool for which job?
  6. Common mistakes
  7. Check yourself
  8. Key takeaways
  9. Quick revise
  10. Practice

Description

Linked-list arithmetic adds numbers stored one digit per node, the way you add on paper: digit by digit from the ones place, carrying into the next column. When the lists hold the digits ones-first, one walk does it. When they hold them in normal reading order, you need a way to reach the ones digits first: stacks, or reversing the lists. It's a small model of how arbitrary-precision numbers work.

We'll go from simple to more technical:

  1. The pattern: add digit by digit, carrying, until both lists and the carry run out.
  2. A second flavor: forward-order digits, using stacks and prepending.
  3. Where digit-by-digit arithmetic runs in production (bignum libraries, money).
  4. The bugs: a dropped final carry, unequal lengths, the wrong build direction.

The approach

When each list stores its number ones digit first, walking both lists from the head is exactly adding by hand from the right. In each column, add the two digits and the carry. Write down the last digit of the sum, and carry the rest into the next column. A list that has run out counts as 0. Keep going while either list or the carry remains.

Adding 958 and 67, stored as 8 -> 5 -> 9 and 7 -> 6:

ColumnFirst digitSecond digitCarry inSumDigit writtenCarry out
Ones8701551
Tens5611221
Hundreds9(none)11001
Thousands(none)(none)1110

The result is 5 -> 2 -> 0 -> 1, which is 1025. The last row exists only because of the carry.

Java

ListNode dummy = new ListNode(0);
ListNode tail = dummy;
int carry = 0;
while (l1 != null || l2 != null || carry != 0) {
    int sum = carry;
    if (l1 != null) { sum += l1.val; l1 = l1.next; }
    if (l2 != null) { sum += l2.val; l2 = l2.next; }
    carry = sum / 10;
    tail.next = new ListNode(sum % 10);
    tail = tail.next;
}
return dummy.next;

Python

def add_two_numbers(l1: ListNode | None, l2: ListNode | None) -> ListNode | None:
    dummy = ListNode(0)
    tail = dummy
    carry = 0
    while l1 is not None or l2 is not None or carry:
        total = carry
        if l1 is not None:
            total += l1.val
            l1 = l1.next
        if l2 is not None:
            total += l2.val
            l2 = l2.next
        carry = total // 10
        tail.next = ListNode(total % 10)
        tail = tail.next
    return dummy.next

Each part of the loop condition handles a case. Checking both lists handles unequal lengths. Checking the carry handles a final carry, like the 1 above. Drop any one, and the code is wrong only on those inputs, which is how such bugs survive casual testing.

A second flavor: forward-order digits need a stack

Now say the digits are stored in normal reading order: 9 -> 5 -> 8 and 6 -> 7. The carry still has to start from the ones digits, but they're at the ends of the lists, and a singly linked list can't be walked backward. So push each list's digits onto a stack. Popping then gives the ones digits first. The result, though, must come out in reading order. So each new digit is put at the front of the result, not the end:

Java

Deque<Integer> s1 = new ArrayDeque<>(), s2 = new ArrayDeque<>();
while (l1 != null) { s1.push(l1.val); l1 = l1.next; }
while (l2 != null) { s2.push(l2.val); l2 = l2.next; }

int carry = 0;
ListNode result = null;
while (!s1.isEmpty() || !s2.isEmpty() || carry != 0) {
    int sum = carry + (s1.isEmpty() ? 0 : s1.pop()) + (s2.isEmpty() ? 0 : s2.pop());
    carry = sum / 10;
    ListNode node = new ListNode(sum % 10);
    node.next = result;     // PREPEND - result must stay in most-significant-first order
    result = node;
}
return result;

Python

def add_two_numbers(l1: ListNode | None, l2: ListNode | None) -> ListNode | None:
    s1, s2 = [], []                  # Python lists work as stacks: append / pop
    for node, stack in ((l1, s1), (l2, s2)):
        while node is not None:
            stack.append(node.val)
            node = node.next
    carry, result = 0, None
    while s1 or s2 or carry:
        total = carry + (s1.pop() if s1 else 0) + (s2.pop() if s2 else 0)
        carry = total // 10
        node = ListNode(total % 10)
        node.next = result           # PREPEND - result must stay in most-significant-first order
        result = node
    return result

The digits come out 5, 2, 0, 1, and prepending each one gives 1 -> 0 -> 2 -> 5. The first digit computed ends up last, which is exactly reading order.

Where you'll see it

Big-number libraries and money calculations that can't use floating point add digit by digit with a carry, just like this. They usually store digits in an array, ones first, so the carry can flow in the natural direction.

Which tool for which job?

You needUse
Add numbers stored ones-digit firstone walk with a carry
Add numbers stored most-significant firsttwo stacks, then prepend each result digit
The same, with O(1) extra spacereverse both lists, add, reverse the result
Multiply digit listsschoolbook: digit pairs into position i + j
Numbers that fit in a machine wordjust convert - if they're guaranteed to fit
Arbitrary size in real codeBigInteger / Python int

Common mistakes

MistakeWhat happensDo this instead
Stopping when both lists end999 + 1 loses its leading 1loop while a list or the carry remains
Assuming equal lengthsnull dereference on the shorter listtreat a finished list as 0
Appending stack-popped digitsthe answer comes out backwardsprepend each new digit
Converting the list to a longoverflows past 18 digitsstay digit by digit
Leading zeros in a product"0042" instead of "42"trim them, keeping one zero

Check yourself

Try to answer before opening each one - recalling beats re-reading.

1. Why does the loop keep going while carry != 0, even after both lists are done?

Show answer

The last column can still produce a carry, as 9 + 1 + 1 = 11 does. That carry must become one more digit, longer than either input. Without the check, the loop stops when the lists run out and the answer loses its first digit.

2. Why do reading-order digits need a stack when ones-first digits don't?

Show answer

The carry flows from the ones digit toward the biggest one. With ones-first storage, that's the direction a singly linked list already walks. With reading order, the ones digit is at the end, and you can't walk backward. A stack reverses the order you reach the digits in, without changing the list.

3. Why prepend each new digit instead of appending it?

Show answer

The digits are computed ones first, but the answer must read biggest first. Prepending puts each new digit in front of all the earlier ones. So the first digit computed ends up last, and the last one computed ends up first.

Key takeaways

  • Loop while either list or the carry remains. Each part of that condition handles a real case.
  • The carry flows from the ones digit up. Ones-first lists already walk that way.
  • Reading-order lists need a stack (or a reversal) to reach the ones digits first.
  • When digits are computed in the opposite order to the output, prepend each one.
  • Both versions take O(max(n, m)) time; the stack version also needs O(n + m) extra space.

Quick revise

The whole skill on one page, for the night before an interview.

Everything from the lesson and the deep dive on one page. Skim it before practice or an interview, and open the full lesson for anything that doesn't ring a bell.

Pick the tool

You needUse
Ones digit firstone walk with a carry
Most significant firststacks + prepend
O(1) space, forward orderreverse, add, reverse
Multiplyschoolbook into i + j
Real codeBigInteger / int

Snippets worth knowing by heart

Java

ListNode dummy = new ListNode(0), tail = dummy;
int carry = 0;
while (l1 != null || l2 != null || carry != 0) {     // the carry can add a digit
    int sum = carry;
    if (l1 != null) { sum += l1.val; l1 = l1.next; }
    if (l2 != null) { sum += l2.val; l2 = l2.next; }
    tail.next = new ListNode(sum % 10);
    tail = tail.next;
    carry = sum / 10;
}
return dummy.next;

Python

s1, s2 = [], []
while l1: s1.append(l1.val); l1 = l1.next
while l2: s2.append(l2.val); l2 = l2.next
head, carry = None, 0
while s1 or s2 or carry:
    total = carry + (s1.pop() if s1 else 0) + (s2.pop() if s2 else 0)
    head = ListNode(total % 10, head)       # prepend: forward order
    carry = total // 10
return head

The traps

  • Dropping the final carry: 999 + 1 loses its leading 1. Loop while a list or the carry remains.
  • Assuming equal lengths: the shorter list hits null. Treat a finished list as 0.
  • Appending in the stack version: popped digits come out backwards. Prepend each new digit.
  • Converting to long: numbers past 18 digits overflow. Stay digit by digit.
  • Leading zeros in products: you return "0042". Trim them, keeping one zero.

Staff-level points, one line each

  • Carry ≤ 1; result ≤ max(n, m) + 1 digits.
  • 25 nines as a Java long: 1590897978359414783.
  • Python int() refuses strings over 4,300 digits (since 3.11).
  • Schoolbook multiply: 60 x 45 digits → 104 digits, O(n m); Karatsuba is faster.
  • Bignums use a big base - 2^30 in CPython (least-significant first), 2^32 in Java - and start at the low digits.

Say it in an interview

  • "I add column by column from the ones digit, carrying into the next."
  • "A finished list counts as zero, and I keep going while there's a carry."
  • "For forward order I use stacks and prepend each digit."
  • "Converting to a number would overflow, so I stay digit by digit."

Practice

This skill comes with 9 multiple-choice questions that tell you which misconception a wrong answer reveals and 2 graded problems. Your answers are graded and your mastery is tracked, so you'll know when the skill holds up. Running code and saving progress need a free account.

Practice Linked List Arithmetic free

Add Two Numbers

MediumProCoding problemJava · Python

Two non-negative numbers are stored as linked lists with one digit per node, ones digit first, so 512 is stored as 2 -> 1 -> 5. Add them and return the sum in the same backwards form.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Add Two Numbers II

MediumProCoding problemJava · Python

This time the digits are stored most significant first, the way you'd write the number, so 512 is 5 -> 1 -> 2. Add the two numbers and return the sum in that same order.

The full statement, the examples and the hidden test suite are part of AI Proof Engineers Pro.

Practice Linked List Arithmetic free

No card needed. Lessons, practice questions and easy problems are free forever.

Free plan, no card · 7-day Pro trial · Cancel anytime