40.Add Two Numbers
Problem
You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order (the head is the ones digit), and each node holds a single digit.
Add the two numbers and return the sum as a linked list in the same reverse-digit format. The numbers have no leading zeros, except the number 0 itself.
Examples
Input: l1 = [2, 4, 3], l2 = [5, 6, 4]
Output: [7, 0, 8]
Explanation: 342 + 465 = 807.Input: l1 = [0], l2 = [0]
Output: [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; the final carry creates a new node.Constraints
- The number of nodes in each linked list is in the range
[1, 100]. 0 <= Node.val <= 9- The lists represent numbers without leading zeros.
๐ก Key Insight
Reverse order is a gift: the heads are the least significant digits, which is exactly where grade-school addition starts. Walk both lists together, add the two digits plus carry, write sum % 10 into a new node and carry sum / 10 forward. Up to 100 digits means the numbers do not fit in long, so converting to primitives is not an option.
Brute Force (BigInteger Conversion)
TimeO(max(m, n)) digit work (BigInteger addition is linear in the number of digits).SpaceO(max(m, n))Intuition
Turn each list into an actual number, add them, and turn the result back into a list. Because a 100-digit number overflows long, we must use BigInteger.
Algorithm
- Build the digit string of each list by prepending digits (reversing the order).
- Parse both strings as
BigIntegerand add them. - Walk the sum's string from the last character to the first, appending a node for each digit.
Visualization
l1 = 2 -> 4 -> 3 => "342"
l2 = 5 -> 6 -> 4 => "465"
342 + 465 = 807 => digits read right-to-left: 7 -> 0 -> 8Code
import java.math.BigInteger;
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
BigInteger sum = toNumber(l1).add(toNumber(l2));
String digits = sum.toString();
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
for (int i = digits.length() - 1; i >= 0; i--) {
tail.next = new ListNode(digits.charAt(i) - '0'); // least significant first
tail = tail.next;
}
return dummy.next;
}
private BigInteger toNumber(ListNode node) {
StringBuilder sb = new StringBuilder();
for (; node != null; node = node.next) {
sb.append(node.val);
}
return new BigInteger(sb.reverse().toString()); // head is the ones digit
}
}Complexity
- Time: O(max(m, n)) digit work (BigInteger addition is linear in the number of digits).
- Space: O(max(m, n)) โ strings and BigInteger objects.
Recursion
TimeO(max(m, n))SpaceO(max(m, n))Intuition
Adding two lists is: add the two head digits plus the incoming carry, make a node for the ones digit, and let recursion handle the rest of both lists with the new carry. Recursion stops when both lists are exhausted and no carry remains.
Algorithm
add(l1, l2, carry):- If
l1,l2are bothnullandcarry == 0, returnnull. sum = carry + (l1 ? l1.val : 0) + (l2 ? l2.val : 0).- Create
node(sum % 10), and setnode.next = add(l1?.next, l2?.next, sum / 10). - Return
node.
- If
Visualization
add(2, 5, 0): sum 7 -> node 7, carry 0
add(4, 6, 0): sum 10 -> node 0, carry 1
add(3, 4, 1): sum 8 -> node 8, carry 0
add(null, null, 0) -> null
result: 7 -> 0 -> 8Code
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
return add(l1, l2, 0);
}
private ListNode add(ListNode l1, ListNode l2, int carry) {
if (l1 == null && l2 == null && carry == 0) {
return null;
}
int sum = carry;
if (l1 != null) sum += l1.val;
if (l2 != null) sum += l2.val;
ListNode node = new ListNode(sum % 10);
node.next = add(l1 == null ? null : l1.next,
l2 == null ? null : l2.next,
sum / 10);
return node;
}
}Complexity
- Time: O(max(m, n)) โ one call per output digit.
- Space: O(max(m, n)) โ recursion depth.
Iterative Digit-by-Digit with CarryOptimal
TimeO(max(m, n))SpaceO(1) extraIntuition
Same arithmetic as the recursion, written as a loop with a dummy head. Keep going while either list has digits or there is a leftover carry โ that last condition is what produces the extra 1 in 999 + 1 = 1000.
Algorithm
dummy,tail = dummy,carry = 0.- While
l1 != null || l2 != null || carry != 0:sum = carry+ digit froml1(if any) + digit froml2(if any).carry = sum / 10; appendnew ListNode(sum % 10).- Advance
l1,l2if non-null.
- Return
dummy.next.
Dry Run
flowchart TD
A["l1 = 2,4,3<br/>l2 = 5,6,4<br/>carry = 0"] -->|"2 + 5 + 0 = 7"| B["append 7, carry 0"]
B -->|"4 + 6 + 0 = 10"| C["append 0, carry 1"]
C -->|"3 + 4 + 1 = 8"| D["append 8, carry 0"]
D -->|"both lists empty, carry 0"| E["return 7 -> 0 -> 8"]Code
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode tail = dummy;
int carry = 0;
// Continue while there are digits left OR a pending carry
while (l1 != null || l2 != null || carry != 0) {
int sum = carry;
if (l1 != null) {
sum += l1.val;
l1 = l1.next;
}
if (l2 != null) {
sum += l2.val;
l2 = l2.next;
}
carry = sum / 10;
tail.next = new ListNode(sum % 10);
tail = tail.next;
}
return dummy.next;
}
}Complexity
- Time: O(max(m, n)) โ one iteration per output digit.
- Space: O(1) extra โ aside from the output list (at most
max(m, n) + 1nodes).
Complexity Comparison
| Approach | Time | Space (extra) |
|---|---|---|
| BigInteger Conversion | O(max(m,n)) | O(max(m,n)) |
| Recursion | O(max(m,n)) | O(max(m,n)) |
| Iterative with Carry | O(max(m,n)) | O(1) |
Common Pitfalls
- Converting to
int/longโ 100-digit numbers overflow immediately. - Forgetting the final carry:
[5] + [5]must return[0, 1], not[0]. - Stopping when the shorter list ends instead of continuing with the longer one.
- Reversing the lists first โ unnecessary, since reverse order already starts at the ones digit.
- Dereferencing
l1.valwithout a null check once one list is exhausted.