Add Two Numbers — Two Approaches
| LeetCode #2 | Difficulty: Medium |
Approach 1: Dummy-Node Version (New List)
Intuition
Each linked list represents a number in reverse order, where each node contains one digit.
To add the two numbers, we simulate elementary addition digit by digit, keeping track of the carry.
Instead of modifying the input lists, we build a new result list using a dummy head node.
This avoids special handling for the first node and makes the implementation simpler and safer.
Approach
- Create a dummy node to serve as the head of the result list.
- Use a pointer
currto build the result list. - Initialize
carry = 0. - Traverse both lists while at least one list has nodes or
carryis non-zero:- Add current digits from
l1andl2(if present) andcarry. - Compute:
digit = sum % 10carry = sum / 10
- Create a new node with
digitand attach it to the result.
- Add current digits from
- Move pointers forward in
l1andl2when possible. - After traversal, return
dummy.nextas the result list.
This handles different list lengths and carry propagation automatically.
Complexity
-
Time complexity:
\(O(max(m, n))\)
Each node of both lists is processed once. -
Space complexity:
\(O(max(m, n))\)
A new list is created to store the result.
Code (Dummy-Node Version)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
ListNode dummy(0);
ListNode* curr = &dummy;
int carry = 0;
while (l1 || l2 || carry) {
int sum = carry;
if (l1) {
sum += l1->val;
l1 = l1->next;
}
if (l2) {
sum += l2->val;
l2 = l2->next;
}
carry = sum / 10;
curr->next = new ListNode(sum % 10);
curr = curr->next;
}
return dummy.next;
}
};
Approach 2: In-Place Version (O(1) Space)
Intuition
The two linked lists represent two non-negative integers in reverse order, where each node stores one digit.
To add these numbers, we simulate manual addition digit by digit, starting from the least significant digit.
At each step, we add the corresponding digits along with a carry and store the result back into the first list.
By modifying l1 in-place, we avoid creating a new linked list.
Approach
- Initialize
carry = 0and usel1as the base list to store the result. - Traverse both lists simultaneously while both have next nodes:
- Add
l1->val,l2->val, andcarry. - Update the current node value with
sum % 10. - Update
carry = sum / 10. - Move both pointers forward.
- Add
- Process the last aligned nodes after the loop.
- If
l1ends beforel2, attach the remaining part ofl2tol1. - Propagate the carry forward in
l1:- Keep adding
carryto remaining nodes.
- Keep adding
- If a carry still remains after reaching the end, create a new node and append it.
- Return the head of
l1as the final result.
This approach performs addition directly on the first list and extends it only when needed.
Complexity
-
Time complexity:
\(O(max(m, n))\)
Each node of both lists is processed at most once. -
Space complexity:
\(O(1)\)
The addition is done in-place without using extra data structures (excluding the possible last node).
Code (In-Place Version)
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) {
int num, carry = 0;
ListNode *head = l1;
while(l1->next && l2->next) {
num = l1->val + l2->val + carry;
carry = num / 10;
num = num % 10;
l1->val = num;
l1 = l1->next;
l2 = l2->next;
}
num = l1->val + l2->val + carry;
carry = num / 10;
num = num % 10;
l1->val = num;
if(!l1->next) { // l1 ends before l2
l1->next = l2->next;
}
ListNode *pre = l1;
l1 = l1->next;
while(carry && l1) {
pre = l1;
num = l1->val + carry;
carry = num / 10;
num = num % 10;
l1->val = num;
l1 = l1->next;
}
if(carry) {
pre->next = new ListNode(carry);
}
return head;
}
};