Topics › Linked List › Medium Problems of LL
Add two numbers in Linked List
LeetCode ↗ Java source ↗ Edit this article ↗
Jump to code:
Problem
Two non-negative integers are given as singly linked lists, one decimal digit per node, with the digits stored in reverse order: the head holds the units digit. Add the two numbers and return the sum as a linked list in the same reversed format. Neither number has leading zeros, except for the number 0 itself, which is the single node 0.
Constraints: each list has 1 ≤ n ≤ 100 nodes (the approaches below work for any length), each digit is 0..9. The lists can be of different lengths.
Example 1
l1 = 2 -> 4 -> 3 // 342
l2 = 5 -> 6 -> 4 // 465
answer = 7 -> 0 -> 8 // 807
Example 2
l1 = 9 -> 9 -> 9 -> 9 -> 9 -> 9 -> 9 // 9999999
l2 = 9 -> 9 -> 9 -> 9 // 9999
answer = 8 -> 9 -> 9 -> 9 -> 0 -> 0 -> 0 -> 1 // 10009998
Example 3
l1 = 0, l2 = 0
answer = 0
Storing the digits in reverse order is deliberate: it makes the units digit the first node, so the carry flows in the same direction as the next pointers.
Approach 1: Brute force, convert to numbers
Intuition. The most literal approach is to turn each list into an integer, add the integers, and write the digits of the sum back into a list. Reading a reversed-digit list into a number is easy: the first node is multiplied by 1, the second by 10, the third by 100, and so on.
Algorithm.
- Convert
l1andl2tolongwithtoLong, multiplying each digit by an increasing power of ten. - Add the two values.
- If the sum is
0, return a single node0. - Otherwise peel digits off the sum with
% 10and/ 10, appending each to a new list behind a dummy head.
static ListNode bruteForce(ListNode l1, ListNode l2) {
long sum = toLong(l1) + toLong(l2);
if (sum == 0) return new ListNode(0);
ListNode dummy = new ListNode(0), tail = dummy;
while (sum > 0) {
tail.next = new ListNode((int) (sum % 10));
tail = tail.next;
sum /= 10;
}
return dummy.next;
}
static long toLong(ListNode head) {
long value = 0, place = 1;
int digits = 0;
for (ListNode t = head; t != null; t = t.next) {
if (++digits > 18) throw new IllegalArgumentException("more than 18 digits: does not fit in a long");
value += t.val * place;
place *= 10;
}
return value;
}
Complexity. Time O(n + m) to read the lists and O(max(n, m)) to write the result. Space O(1) apart from the output list.
Why this is not acceptable. A long holds at most 18 full decimal digits. The linked-list representation exists precisely so numbers can be arbitrarily long, and a 19-digit input silently overflows into garbage. toLong throws instead of returning a wrong answer, and the test file checks that it does on a 25-digit input. BigInteger would avoid the overflow, but it is heavier than the problem deserves, and it would hide the digit-level reasoning that the interviewer wants to see.
Approach 2: Better, digit-by-digit with a carry into a new list
Intuition. Do what the brute force does, but never materialise the whole number. Walk both lists in lockstep. At each position the result digit is (a + b + carry) % 10 and the new carry is (a + b + carry) / 10. When one list runs out, treat its missing digits as 0. When both lists are exhausted and the carry is still 1, that carry is one more digit. A dummy head makes appending to the result uniform.
Algorithm.
- Create a dummy node and a
tailpointer at it; setcarry = 0. - While
l1orl2still has a node, orcarryis non-zero:sum = carry, plusl1.valifl1exists (then advancel1), plusl2.valifl2exists (then advancel2).- Append a node holding
sum % 10; setcarry = sum / 10.
- Return
dummy.next.
static ListNode better(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0), tail = dummy;
int carry = 0;
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; }
tail.next = new ListNode(sum % 10);
tail = tail.next;
carry = sum / 10;
}
return dummy.next;
}
Complexity. Time O(max(n, m)): one step per result digit, and the result has at most max(n, m) + 1 digits. Space O(max(n, m)) for the newly built answer, O(1) otherwise.
The loop condition || carry != 0 is the detail most people forget: it is what turns 5 + 5 into 0 -> 1 instead of just 0. Since each digit is at most 9, sum ≤ 9 + 9 + 1 = 19, so the carry is always 0 or 1 and the extra iteration happens at most once.
Why “better” rather than “optimal”? This version is the one to write in an interview: it is short, obviously correct, and leaves the inputs untouched. Its only cost is that it allocates a brand-new node for every digit of the result.
Approach 3: Optimal, reuse the nodes of the inputs
Intuition. The answer has the same length as the longer input, plus possibly one node. So instead of allocating a fresh list, we can overwrite the digits of l1 in place and, when l2 is longer, splice l2’s leftover tail onto the result. At most one new node is ever created, for a final carry.
Algorithm.
- If either list is empty, the other list is the answer.
- Remember
head = l1. Walk while both lists have nodes: write(l1.val + l2.val + carry) % 10intol1, update the carry, rememberprev = l1, advance both. - If
l1ran out first, attach the remainder ofl2afterprevand continue on it (l1 = l2). - While nodes remain and the carry is non-zero, add the carry into the current node and advance.
- If the carry is still non-zero after the last node, append one new node holding it.
- Return
head.
static ListNode optimal(ListNode l1, ListNode l2) {
if (l1 == null) return l2;
if (l2 == null) return l1;
ListNode head = l1, prev = null;
int carry = 0;
while (l1 != null && l2 != null) { // digits present in both numbers
int sum = l1.val + l2.val + carry;
l1.val = sum % 10;
carry = sum / 10;
prev = l1;
l1 = l1.next;
l2 = l2.next;
}
if (l1 == null) { // l2 is longer: continue on l2's remaining nodes
prev.next = l2;
l1 = l2;
}
while (l1 != null && carry != 0) { // push the carry through the remaining digits
int sum = l1.val + carry;
l1.val = sum % 10;
carry = sum / 10;
prev = l1;
l1 = l1.next;
}
if (carry != 0) prev.next = new ListNode(carry); // ran out of digits with a carry left: one new node
return head;
}
Dry run on l1 = 9 -> 9, l2 = 1:
| phase | l1.val | l2.val | carry in | written | carry out |
|---|---|---|---|---|---|
| both lists | 9 | 1 | 0 | 0 | 1 |
| l2 exhausted, l1 continues | 9 | - | 1 | 0 | 1 |
| no nodes left, carry 1 | - | - | 1 | new node 1 | 0 |
Result: 0 -> 0 -> 1, which is 99 + 1 = 100.
Complexity. Time O(max(n, m)), the same as Approach 2. Space O(1) extra: the result reuses existing nodes and allocates at most one.
The second loop stops as soon as the carry is 0. Any digits after that point belong to the longer input and are already correct, and since prev.next still points at them, they remain part of the result without being visited.
The price of this approach is that it destroys l1 (and borrows l2’s tail). That is fine when the inputs are throwaway, and it is the version to mention when an interviewer asks for O(1) extra space.
Edge cases and pitfalls
- Different lengths.
1+9 -> 9and9 -> 9+1must both give0 -> 0 -> 1. Approach 3 is asymmetric in which list it reuses, so the test file runs it with the arguments in both orders. - Final carry.
5 + 5 = 0 -> 1, and9999999 + 9999grows to eight digits. Any loop that stops when both lists end, without checking the carry, drops the most significant digit. - Both zero.
0 + 0must return0, not an empty list. The brute force needs an explicit check for a zero sum because its digit-peeling loop would otherwise produce nothing. - Overflow. Converting to
intorlongworks only up to 9 or 18 digits. Digit-by-digit addition has no such limit; the test includes two 25-digit numbers. - Leading zeros in the output. Because digits are stored in reverse, a “leading” zero would be a trailing node. The carry logic never produces one: the last node written is either a real digit or a carry of
1. - Mutation. Approach 3 modifies its inputs; Approaches 1 and 2 do not. Choose according to whether the caller still needs the originals.
Related problems
- Add one to a number represented by LL is the special case of adding a single
1, with digits stored in forward order. - Add two numbers as LinkedList is the SDE sheet entry for this same problem.
- Reverse a LL is what you need first if the digits were given most significant first.
- Merge two Sorted Lists uses the same “walk two lists in lockstep behind a dummy head” pattern.