2. Add Two Numbers - Explanation
Description
You are given two non-empty linked lists, l1 and l2, where each represents a non-negative integer.
The digits are stored in reverse order, e.g. the number 321 is represented as 1 -> 2 -> 3 -> in the linked list.
Each of the nodes contains a single digit. You may assume the two numbers do not contain any leading zero, except the number 0 itself.
Return the sum of the two numbers as a linked list.
Example 1:
Input: l1 = [1,2,3], l2 = [4,5,6]
Output: [5,7,9]
Explanation: 321 + 654 = 975.Example 2:
Input: l1 = [9], l2 = [9]
Output: [8,1]Constraints:
1 <= l1.length, l2.length <= 100.0 <= Node.val <= 9
Topics
Recommended Time & Space Complexity
You should aim for a solution with O(m + n) time and O(1) space, where m is the length of list l1 and n is the length of list l2.
Hint 1
Try to visualize the addition of two numbers. We know that the addition of two numbers is done by starting at the one's digit. We add the numbers by going through digit by digit. We track the extra value as a carry because the addition of two digits can result in a number with two digits. The carry is then added to the next digits, and so on. How do you implement this in case of linked lists?
Hint 2
We track the extra value, carry, here as well. We iterate through the lists l1 and l2 until both lists reach null. We add the values of both nodes as well as the carry. If either of the nodes is null, we add 0 in its place and continue the process while tracking the carry simultaneously. Once we complete the process, if we are left with any carry, we add an extra node with that carry value and return the head of the result list.
Prerequisites
Before attempting this problem, you should be comfortable with:
- Linked Lists - Traversing and creating new nodes in a singly linked list
- Recursion - Understanding how to break down problems into smaller subproblems
- Carry Propagation - How carry works when adding numbers digit by digit
1. Recursion
Intuition
We add the two linked lists exactly like adding two numbers on paper.
Each node contains one digit, and since the lists are stored in reverse order, the head contains the ones place — making addition easy.
At every step:
- Take a digit from
l1(or0if it's finished) - Take a digit from
l2(or0if it's finished) - Add them with the incoming
carry - Create a new node for the current digit (
sum % 10) - Pass the new
carry(sum // 10) forward using recursion
The recursion naturally processes digits from left to right and stops only when:
- both lists are fully processed and
- no carry remains.
Algorithm
Define a recursive function
add(l1, l2, carry):- If
l1,l2are bothNoneandcarryis0, returnNone. - Extract:
v1 = l1.valifl1exists, else0v2 = l2.valifl2exists, else0
- Compute:
total = v1 + v2 + carrycarry, digit = divmod(total, 10)
- Recursively compute the next node using:
l1.nextif existsl2.nextif exists- updated
carry
- Return a node with value
digitwhosenextis the recursive result.
- If
In
addTwoNumbers, call:return add(l1, l2, 0)
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def add(self, l1: Optional[ListNode], l2: Optional[ListNode], carry: int) -> Optional[ListNode]:
if not l1 and not l2 and carry == 0:
return None
v1 = l1.val if l1 else 0
v2 = l2.val if l2 else 0
carry, val = divmod(v1 + v2 + carry, 10)
next_node = self.add(
l1.next if l1 else None,
l2.next if l2 else None,
carry
)
return ListNode(val, next_node)
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
return self.add(l1, l2, 0)Time & Space Complexity
- Time complexity:
- This is asymptotically equivalent to .
- Space complexity:
- for the recursion call stack.
- for the output list.
Where is the length of and is the length of .
2. Iteration
Intuition
We simulate normal addition the same way we do on paper — digit by digit.
The linked lists store numbers in reverse order, so the first nodes represent the 1’s place.
This makes addition straightforward:
- Add the two digits.
- Add the
carryfrom the previous step. - Save the resulting digit (
sum % 10) into a new node. - Update the
carry(sum // 10). - Move both pointers forward.
We continue until both lists are finished AND no carry remains.
A dummy node helps us easily build and return the final linked list.
Algorithm
Create:
- A
dummynode (to build the answer) - A pointer
curpointing todummy - An integer
carry = 0
- A
Loop while
l1exists,l2exists, orcarryis non-zero:- Read the current digit of each list (
0if that list already ended) - Compute
sum = v1 + v2 + carry - Update:
carry = sum // 10digit = sum % 10 - Append a new node containing
digit - Move the pointers
l1,l2, andcurforward
- Read the current digit of each list (
Return
dummy.next(the head of the result list)
This ensures correct handling of:
- different lengths of input lists
- leftover carry
- building the result in one pass
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]:
dummy = ListNode()
cur = dummy
carry = 0
while l1 or l2 or carry:
v1 = l1.val if l1 else 0
v2 = l2.val if l2 else 0
# new digit
val = v1 + v2 + carry
carry = val // 10
val = val % 10
cur.next = ListNode(val)
# update ptrs
cur = cur.next
l1 = l1.next if l1 else None
l2 = l2.next if l2 else None
return dummy.nextTime & Space Complexity
- Time complexity:
- This is asymptotically equivalent to .
- Space complexity:
- extra space.
- for the output list.
Where is the length of and is the length of .
Common Pitfalls
Forgetting the Final Carry
When both lists are exhausted, there may still be a carry of 1 (e.g., 999 + 1 = 1000). Stopping the loop early without checking for remaining carry produces an incorrect result.
# Wrong: missing carry check
while l1 or l2: # Should be: while l1 or l2 or carry
# ...Not Handling Lists of Different Lengths
When one list is longer than the other, the loop must continue processing the remaining nodes. Using l1 and l2 instead of l1 or l2 stops too early.
# Wrong: requires both lists to have nodes
while l1 and l2: # Stops when either list ends
# ...
Sign in to join the discussion