A detailed explanation of the Add Two Numbers linked list problem, including digit-by-digit addition, carry handling, and linked list construction.
Problem Restatement
We are given two non-empty linked lists.
Each linked list represents a non-negative integer.
The digits are stored in reverse order.
For example:
2 -> 4 -> 3actually represents the number:
342because the least significant digit comes first.
We need to add the two numbers together and return the result as a linked list in the same reversed format.
Each node contains exactly one digit.
Input and Output
| Item | Meaning |
|---|---|
| Input | Two linked lists l1 and l2 |
| Output | A new linked list representing the sum |
| Digit Order | Reverse order |
| Constraint | Each node stores one digit from 0 to 9 |
The linked list node structure:
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = nextExamples
Input:
l1 = 2 -> 4 -> 3
l2 = 5 -> 6 -> 4The first list represents:
342The second list represents:
465Their sum is:
342 + 465 = 807Because the output must also be reversed, we return:
7 -> 0 -> 8Another example:
l1 = 0
l2 = 0Result:
0Another example:
l1 = 9 -> 9 -> 9 -> 9
l2 = 1This represents:
9999 + 1 = 10000Result:
0 -> 0 -> 0 -> 0 -> 1The final carry creates a new node.
First Thought: Convert Everything Into Integers
One possible idea:
- Traverse the linked list.
- Convert the digits into integers.
- Add the integers.
- Convert the result back into a linked list.
For small numbers, this works.
Example:
2 -> 4 -> 3becomes:
342Then:
342 + 465 = 807Finally:
7 -> 0 -> 8Problem With Integer Conversion
This approach has several issues.
The linked lists may become very large.
Some languages cannot safely store extremely large integers.
More importantly, the problem is designed to test linked list manipulation and digit-by-digit arithmetic.
We should solve the problem directly using the linked lists themselves.
Key Insight
This problem behaves exactly like elementary school addition.
When adding two numbers by hand:
- Add the current digits.
- Add the carry from the previous step.
- Write down the current digit.
- Carry the overflow into the next column.
Example:
342
+ 465
-----
807Digit by digit:
2 + 5 = 7
4 + 6 = 10
3 + 4 + 1 = 8The linked lists already store digits from least significant to most significant.
That means we can process them naturally from left to right.
Visual Walkthrough
Start:
l1: 2 -> 4 -> 3
l2: 5 -> 6 -> 4
carry = 0First digits:
2 + 5 + 0 = 7Write digit:
7New carry:
0Second digits:
4 + 6 + 0 = 10Write digit:
0Carry:
1Third digits:
3 + 4 + 1 = 8Write digit:
8Carry:
0Final result:
7 -> 0 -> 8Algorithm
We maintain:
| Variable | Meaning |
|---|---|
carry | Overflow from previous digit |
dummy | Fake head node for easier construction |
current | Tail of the result list |
Loop while:
l1still exists- or
l2still exists - or
carryis non-zero
For every step:
- Read the current digit from
l1 - Read the current digit from
l2 - Add both digits and the carry
- Compute:
- new digit
- new carry
- Create a new node
- Move forward
The important formulas are:
Current digit:
New carry:
Correctness
At every iteration, we process exactly one decimal position.
Suppose:
xis the current digit froml1yis the current digit froml2carryis the overflow from the previous position
Then:
x + y + carryrepresents the correct sum for the current decimal place.
The ones digit becomes the node value.
The tens digit becomes the carry for the next iteration.
This matches exactly how decimal addition works.
The loop continues until:
- both linked lists are exhausted
- and no carry remains
Therefore every digit of the final sum is constructed correctly.
Complexity
| Metric | Value | Why |
|---|---|---|
| Time | O(max(n, m)) | We traverse each list once |
| Space | O(max(n, m)) | The result list stores the sum |
Where:
nis the length ofl1mis the length ofl2
Implementation
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def addTwoNumbers(
self,
l1: ListNode,
l2: ListNode
) -> ListNode:
dummy = ListNode()
current = dummy
carry = 0
while l1 or l2 or carry:
x = l1.val if l1 else 0
y = l2.val if l2 else 0
total = x + y + carry
digit = total % 10
carry = total // 10
current.next = ListNode(digit)
current = current.next
if l1:
l1 = l1.next
if l2:
l2 = l2.next
return dummy.nextCode Explanation
We first create a dummy node:
dummy = ListNode()This simplifies linked list construction.
Without a dummy node, we would need special handling for the first element.
current always points to the tail of the result list.
current = dummyWe maintain the carry:
carry = 0Inside the loop:
x = l1.val if l1 else 0
y = l2.val if l2 else 0If one list becomes shorter, we treat missing digits as 0.
Then:
total = x + y + carryExtract the new digit:
digit = total % 10Extract the carry:
carry = total // 10Create the next node:
current.next = ListNode(digit)Move forward:
current = current.nextFinally:
return dummy.nextWe skip the dummy node and return the real head.
Testing
Helper functions:
def build_list(values):
dummy = ListNode()
current = dummy
for v in values:
current.next = ListNode(v)
current = current.next
return dummy.next
def to_list(node):
result = []
while node:
result.append(node.val)
node = node.next
return resultTests:
def run_tests():
s = Solution()
l1 = build_list([2, 4, 3])
l2 = build_list([5, 6, 4])
assert to_list(s.addTwoNumbers(l1, l2)) == [7, 0, 8]
l1 = build_list([0])
l2 = build_list([0])
assert to_list(s.addTwoNumbers(l1, l2)) == [0]
l1 = build_list([9, 9, 9, 9])
l2 = build_list([1])
assert to_list(s.addTwoNumbers(l1, l2)) == [0, 0, 0, 0, 1]
l1 = build_list([1, 8])
l2 = build_list([0])
assert to_list(s.addTwoNumbers(l1, l2)) == [1, 8]
print("all tests passed")
run_tests()| Test | Why |
|---|---|
| Standard example | Basic correctness |
| Zero values | Smallest valid input |
| Final carry overflow | Checks extra node creation |
| Different list lengths | Confirms missing digits handled correctly |