title: Add Two Numbers slug: add-two-numbers difficulty: medium leetcode_id: 2 leetcode_url: https://leetcode.com/problems/add-two-numbers/ categories: - linked-lists - math patterns: - two-pointers function_signature: "def add_two_numbers(l1: ListNode | None, l2: ListNode | None) -> ListNode | None:" test_cases: visible: - input: { l1: [2, 4, 3], l2: [5, 6, 4] } expected: [7, 0, 8] - input: { l1: [0], l2: [0] } expected: [0] - input: { l1: [9, 9, 9, 9, 9, 9, 9], l2: [9, 9, 9, 9] } expected: [8, 9, 9, 9, 0, 0, 0, 1] hidden: - input: { l1: [1], l2: [9, 9] } expected: [0, 0, 1] - input: { l1: [5], l2: [5] } expected: [0, 1] description: | 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: - input: "l1 = [2,4,3], l2 = [5,6,4]" output: "[7,0,8]" explanation: "342 + 465 = 807. Digits are stored in reverse order." - input: "l1 = [0], l2 = [0]" output: "[0]" explanation: "0 + 0 = 0" - input: "l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]" output: "[8,9,9,9,0,0,0,1]" explanation: "9999999 + 9999 = 10009998" explanation: intuition: | The digits are stored in **reverse order**, which is actually perfect for addition! Think about how you add numbers by hand: you start from the rightmost digit (ones place), add, carry the overflow, and move left. Here, the "rightmost" digit is conveniently at the head of the list. Think of it like this: we're simulating elementary school addition, digit by digit: 1. Add corresponding digits from both numbers 2. If the sum is ≥ 10, keep the ones digit and carry 1 to the next position 3. Move to the next digit and repeat The key insight is that we process both lists in parallel, handling cases where: - One list is longer than the other (treat missing digits as 0) - There's a carry after processing both lists (add an extra digit) approach: | We solve this using **Iterative Digit-by-Digit Addition**: **Step 1: Initialise the result list and carry** - Create a `dummy` head node (simplifies result construction) - Set `current` to point to `dummy` - Set `carry = 0`   **Step 2: Process digits from both lists** - While `l1` is not None OR `l2` is not None OR `carry` is non-zero: - Get `val1 = l1.val if l1 else 0` - Get `val2 = l2.val if l2 else 0` - Compute `total = val1 + val2 + carry` - Create new node with `total % 10` (ones digit) - Update `carry = total // 10` (tens digit, if any) - Advance `l1` and `l2` if they have more nodes   **Step 3: Return the result** - Return `dummy.next` (skip the dummy head)   The condition `l1 or l2 or carry` ensures we handle all cases: unequal lengths and final carry. common_pitfalls: - title: Forgetting the Final Carry description: | After both lists are exhausted, there might still be a carry. For example, 99 + 1 = 100 — the final carry creates an extra digit. The loop condition `while l1 or l2 or carry` handles this by continuing as long as there's a carry to process. wrong_approach: "while l1 or l2 — stops even if carry is 1" correct_approach: "while l1 or l2 or carry" - title: Assuming Equal Length Lists description: | The two lists can have different lengths. When one list is exhausted, treat its "digits" as 0. Use `val1 = l1.val if l1 else 0` to handle this gracefully. wrong_approach: "while l1 and l2 — stops when either is exhausted" correct_approach: "Use 0 for missing digits: val = node.val if node else 0" - title: Converting to Integers description: | Don't convert the lists to integers, add them, and convert back. The numbers can have up to 100 digits, far exceeding standard integer limits in many languages. Process digit by digit to avoid overflow issues. wrong_approach: "num1 = int(digits1); result = num1 + num2" correct_approach: "Add digit by digit with carry" key_takeaways: - "**Dummy head simplifies linked list construction**: No special case for the first node" - "**Digit-by-digit avoids overflow**: Works with arbitrarily large numbers" - "**Handle unequal lengths gracefully**: Treat missing nodes as 0" - "**Don't forget the final carry**: The loop condition should include `or carry`" time_complexity: "O(max(m, n)). We traverse both lists once, processing max(m, n) digits where m and n are the list lengths." space_complexity: "O(max(m, n)). The result list has at most max(m, n) + 1 nodes (extra node for carry)." solutions: - approach_name: Iterative with Carry is_optimal: true code: | class ListNode: def __init__(self, val=0, next=None): self.val = val self.next = next def add_two_numbers(l1: ListNode | None, l2: ListNode | None) -> ListNode | None: dummy = ListNode() # Dummy head for easy result construction current = dummy carry = 0 # Continue while there are digits to process or carry to add while l1 or l2 or carry: # Get current digits (0 if list is exhausted) val1 = l1.val if l1 else 0 val2 = l2.val if l2 else 0 # Add digits and carry total = val1 + val2 + carry carry = total // 10 # Carry for next position digit = total % 10 # Current digit # Create new node and advance current.next = ListNode(digit) current = current.next # Advance input pointers if possible l1 = l1.next if l1 else None l2 = l2.next if l2 else None return dummy.next explanation: | **Time Complexity:** O(max(m, n)) — Single pass through both lists. **Space Complexity:** O(max(m, n)) — Result list size. We simulate manual addition: add corresponding digits plus carry, store the ones digit, propagate the carry. The dummy head eliminates special handling for the first node. The loop continues until both lists are exhausted AND there's no remaining carry. - approach_name: Recursive is_optimal: false code: | def add_two_numbers( l1: ListNode | None, l2: ListNode | None, carry: int = 0 ) -> ListNode | None: # Base case: both lists empty and no carry if not l1 and not l2 and not carry: return None # Get current digit values val1 = l1.val if l1 else 0 val2 = l2.val if l2 else 0 # Calculate sum and create node total = val1 + val2 + carry node = ListNode(total % 10) # Recurse for remaining digits node.next = add_two_numbers( l1.next if l1 else None, l2.next if l2 else None, total // 10 ) return node explanation: | **Time Complexity:** O(max(m, n)) — Same as iterative. **Space Complexity:** O(max(m, n)) — Recursion stack depth. Recursive version processes one digit per call. Each call creates a node and recursively handles the rest. Elegant but uses stack space proportional to input length.