← Back to All Algorithms

Medium Interview Frequency: ⭐⭐⭐⭐

Add Two Numbers

You are given two non-empty linked lists representing two non-negative integers in reverse order. Add the two numbers and return the sum as a linked list.

📚 Table of Contents

  1. Problem Statement
  2. Real-World Analogy
  3. Key Insights
  4. Solution Approaches
  5. Step-by-Step Walkthrough
  6. Complexity Analysis
  7. Edge Cases
  8. Test Cases
  9. Interview Tips
  10. Key Takeaways

📋 Problem Statement

Each linked list node stores one digit. Digits are stored in reverse order: the ones place appears first, then tens, hundreds, and so on.

Return a new linked list representing the sum, also in reverse order.

Examples

Example 1:
Input: l1 = [2,4,3], l2 = [5,6,4]
Output: [7,0,8]
342 + 465 = 807
Example 2:
Input: l1 = [0], l2 = [0]
Output: [0]
Example 3:
Input: l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]
Output: [8,9,9,9,0,0,0,1]

Constraints

🎯 Real-World Analogy

Cash Register Tape Addition

Imagine you are adding two long receipts where each line is a digit column. You start from the smallest unit (cents), write the result digit, and carry any overflow to the next line.

A linked list here behaves like that receipt tape: one digit at a time, moving forward. You never need the full number materialized as one giant integer.

This is why a digit-by-digit traversal with a carry variable is the clean, scalable approach.

💡 Key Insights

💻 Solution Approaches

Approach 1: Convert to Integers (Not Preferred)

Time: O(N + M) | Space: O(N + M)

Convert both linked lists to integers, add them, then rebuild a linked list. This is easy conceptually but can overflow in languages without arbitrary precision and adds conversion overhead.

Approach 2: In-Place Digit Addition (Recommended)

Time: O(max(N, M)) | Space: O(max(N, M)) for result list

Traverse both lists together, compute one digit at a time, and propagate carry forward.

Python Implementation

class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def add_two_numbers(l1: ListNode, l2: ListNode) -> ListNode: """ Add two numbers represented as reverse-order linked lists. Time: O(max(N, M)) Space: O(max(N, M)) """ dummy = ListNode(0) tail = dummy carry = 0 while l1 or l2 or carry: v1 = l1.val if l1 else 0 v2 = l2.val if l2 else 0 total = v1 + v2 + carry carry = total // 10 digit = total % 10 tail.next = ListNode(digit) tail = tail.next if l1: l1 = l1.next if l2: l2 = l2.next return dummy.next

JavaScript Implementation

function ListNode(val, next) { this.val = val === undefined ? 0 : val; this.next = next === undefined ? null : next; } function addTwoNumbers(l1, l2) { /** * Add two reverse-order linked-list numbers. * * Time: O(max(N, M)) * Space: O(max(N, M)) */ const dummy = new ListNode(0); let tail = dummy; let carry = 0; while (l1 !== null || l2 !== null || carry > 0) { const v1 = l1 ? l1.val : 0; const v2 = l2 ? l2.val : 0; const total = v1 + v2 + carry; carry = Math.floor(total / 10); const digit = total % 10; tail.next = new ListNode(digit); tail = tail.next; if (l1) l1 = l1.next; if (l2) l2 = l2.next; } return dummy.next; }

🔍 Step-by-Step Walkthrough

Trace l1 = [2,4,3] and l2 = [5,6,4]:

Start: carry = 0, result = []

Step 1: 2 + 5 + 0 = 7
digit = 7, carry = 0
result = [7]
Step 2: 4 + 6 + 0 = 10
digit = 0, carry = 1
result = [7, 0]
Step 3: 3 + 4 + 1 = 8
digit = 8, carry = 0
result = [7, 0, 8]
Final: [7, 0, 8]

⚡ Complexity Analysis

Time Complexity: O(max(N, M))

Space Complexity: O(max(N, M))

Trade-off vs Integer Conversion

Approach Time Space Risk
Convert to integers O(N + M) O(N + M) Potential overflow / conversion complexity
Digit-by-digit linked list addition O(max(N, M)) O(max(N, M)) None; directly matches data structure

🔧 Edge Cases

🧪 Test Cases

Case 1
[2,4,3] + [5,6,4] -> [7,0,8]
Case 2
[9,9,9] + [1] -> [0,0,0,1]
Case 3
[0] + [0] -> [0]

💼 Interview Tips

What interviewers probe:

🎓 Key Takeaways

← Back to All Algorithms