Skip to main content

31. Add Two Numbers

mediumAsked at Plaid

Add two numbers represented as reverse-order linked lists. Plaid asks this because adding two arbitrary-precision balances digit-by-digit with carry is exactly how their ledger code handles cents that overflow JS Number precision.

By Alex Chen, Founder, InterviewChamp.AI · Last verified

Source citations

Public interview reports confirming this problem appears in Plaid loops.

  • Glassdoor (2025)Plaid SWE II onsite — framed as ledger arbitrary-precision add.
  • Blind (2026)Plaid backend screen.

Problem

You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order, and each of their nodes contains a single digit. Add the two numbers and return the sum as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself.

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.

Examples

Example 1

Input
l1 = [2,4,3], l2 = [5,6,4]
Output
[7,0,8]

Explanation: 342 + 465 = 807

Example 2

Input
l1 = [0], l2 = [0]
Output
[0]

Approaches

1. Convert to numbers, add, convert back

Reverse each list into a string, BigInt-add, rebuild a list.

Time
O(n+m)
Space
O(n+m)
function addTwoNumbers(l1, l2) {
  function toBig(l) {
    let s = '';
    for (let n = l; n; n = n.next) s = n.val + s;
    return BigInt(s);
  }
  const sum = (toBig(l1) + toBig(l2)).toString();
  let head = null;
  for (const ch of sum) head = { val: +ch, next: head };
  return head;
}

Tradeoff: Dodges the carry-propagation algorithm. Plaid wants the digit-by-digit loop.

2. Digit-by-digit with carry

Walk both lists in lockstep, summing digit + digit + carry. Emit (sum % 10) as the next node; carry = (sum / 10) | 0.

Time
O(max(n, m))
Space
O(max(n, m))
function addTwoNumbers(l1, l2) {
  const dummy = { next: null };
  let cur = dummy, carry = 0;
  while (l1 || l2 || carry) {
    const a = l1 ? l1.val : 0;
    const b = l2 ? l2.val : 0;
    const sum = a + b + carry;
    carry = (sum / 10) | 0;
    cur.next = { val: sum % 10, next: null };
    cur = cur.next;
    if (l1) l1 = l1.next;
    if (l2) l2 = l2.next;
  }
  return dummy.next;
}

Tradeoff: Single pass, handles unequal lengths and final carry inside the same loop. The 'while (l1 || l2 || carry)' is the trick that unifies three cases.

Plaid-specific tips

Plaid loves this because it mirrors their ledger math — never store balances as JS Number (precision loss), always carry digit-by-digit. Bonus signal: explicitly mention 'I'm tracking carry separately because final overflow is a digit, not a discard.' That maps to fee+principal+interest summing in their billing pipeline.

Common mistakes

  • Forgetting the trailing carry — sum of [9,9] + [1] is [0,0,1], not [0,0].
  • Looping only while both l1 and l2 — drops the longer list.
  • Using (sum / 10) without the | 0 floor — JS gives a float.

Follow-up questions

An interviewer at Plaid may pivot to one of these next:

  • What if digits are stored in forward order (LC 445)? — reverse first or use a stack.
  • Multiply two numbers represented as lists.
  • Big-int add for two arrays of digits (LC 989).

Solve it now

Free. No sign-up. Python and JavaScript run instantly in your browser.

Output

Press Run or Cmd+Enter to execute

FAQ

Why digit-by-digit instead of BigInt?

BigInt works but obscures the algorithm. In production, ledger math is digit-by-digit (or cents-as-integers) because that's auditable and precision-safe.

Why the dummy head?

Removes the special case for the first node — without it you'd need an if-statement to set the head separately.

Practice these live with InterviewChamp.AI

Drill Add Two Numbers and other Plaid interview questions under real-loop conditions with instant feedback on your reasoning, complexity claims, and code.

Practice these live with InterviewChamp.AI →