💡 This approach uses recursion to add digits and carry, which can be more elegant but risks stack overflow for very long lists. It helps understand the problem from a different perspective.
Intuition
Add the current digits and carry, create a node for the sum digit, then recursively add the next nodes and carry until all nodes and carry are processed.
Algorithm
- Define a recursive function that takes two nodes and a carry.
- If both nodes and carry are zero/null, return null (base case).
- Sum the values of the current nodes and carry.
- Create a new node with the digit part of the sum.
- Recursively call the function for next nodes and updated carry.
- Link the new node's next to the recursive call result.
💡 The recursion handles the traversal and carry propagation implicitly, but managing base cases and null nodes is critical.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def addTwoNumbersRecursive(l1, l2, carry=0):
if not l1 and not l2 and carry == 0:
return None
val1 = l1.val if l1 else 0
val2 = l2.val if l2 else 0
total = val1 + val2 + carry
carry = total // 10
node = ListNode(total % 10)
next1 = l1.next if l1 else None
next2 = l2.next if l2 else None
node.next = addTwoNumbersRecursive(next1, next2, carry)
return node
# Driver code
if __name__ == '__main__':
def create_list(arr):
dummy = ListNode(0)
cur = dummy
for num in arr:
cur.next = ListNode(num)
cur = cur.next
return dummy.next
l1 = create_list([2,4,3])
l2 = create_list([5,6,4])
result = addTwoNumbersRecursive(l1, l2)
while result:
print(result.val, end=' ')
result = result.next
print()
Line Notes
if not l1 and not l2 and carry == 0:Base case: no nodes and no carry means addition is complete
val1 = l1.val if l1 else 0Use 0 if l1 is exhausted to handle different lengths
total = val1 + val2 + carrySum current digits and carry
node = ListNode(total % 10)Create node for current digit
node.next = addTwoNumbersRecursive(next1, next2, carry)Recursive call for next digits and carry
return nodeReturn current node to link with previous
class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
}
public class Solution {
public ListNode addTwoNumbersRecursive(ListNode l1, ListNode l2, int carry) {
if (l1 == null && l2 == null && carry == 0) return null;
int val1 = (l1 != null) ? l1.val : 0;
int val2 = (l2 != null) ? l2.val : 0;
int total = val1 + val2 + carry;
carry = total / 10;
ListNode node = new ListNode(total % 10);
ListNode next1 = (l1 != null) ? l1.next : null;
ListNode next2 = (l2 != null) ? l2.next : null;
node.next = addTwoNumbersRecursive(next1, next2, carry);
return node;
}
public static void main(String[] args) {
Solution sol = new Solution();
ListNode l1 = createList(new int[]{2,4,3});
ListNode l2 = createList(new int[]{5,6,4});
ListNode result = sol.addTwoNumbersRecursive(l1, l2, 0);
printList(result);
}
private static ListNode createList(int[] arr) {
ListNode dummy = new ListNode(0);
ListNode cur = dummy;
for (int num : arr) {
cur.next = new ListNode(num);
cur = cur.next;
}
return dummy.next;
}
private static void printList(ListNode node) {
while (node != null) {
System.out.print(node.val + " ");
node = node.next;
}
System.out.println();
}
}
Line Notes
if (l1 == null && l2 == null && carry == 0) return null;Base case: no nodes and no carry means addition complete
int val1 = (l1 != null) ? l1.val : 0;Use 0 if l1 is exhausted to handle different lengths
int total = val1 + val2 + carry;Sum current digits and carry
ListNode node = new ListNode(total % 10);Create node for current digit
node.next = addTwoNumbersRecursive(next1, next2, carry);Recursive call for next digits and carry
return node;Return current node to link with previous
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
class Solution {
public:
ListNode* addTwoNumbersRecursive(ListNode* l1, ListNode* l2, int carry) {
if (!l1 && !l2 && carry == 0) return nullptr;
int val1 = l1 ? l1->val : 0;
int val2 = l2 ? l2->val : 0;
int total = val1 + val2 + carry;
carry = total / 10;
ListNode* node = new ListNode(total % 10);
ListNode* next1 = l1 ? l1->next : nullptr;
ListNode* next2 = l2 ? l2->next : nullptr;
node->next = addTwoNumbersRecursive(next1, next2, carry);
return node;
}
};
// Helper functions for testing
ListNode* createList(int arr[], int n) {
ListNode dummy(0);
ListNode* cur = &dummy;
for (int i = 0; i < n; i++) {
cur->next = new ListNode(arr[i]);
cur = cur->next;
}
return dummy.next;
}
void printList(ListNode* node) {
while (node) {
cout << node->val << " ";
node = node->next;
}
cout << endl;
}
int main() {
Solution sol;
int arr1[] = {2,4,3};
int arr2[] = {5,6,4};
ListNode* l1 = createList(arr1, 3);
ListNode* l2 = createList(arr2, 3);
ListNode* result = sol.addTwoNumbersRecursive(l1, l2, 0);
printList(result);
return 0;
}
Line Notes
if (!l1 && !l2 && carry == 0) return nullptr;Base case: no nodes and no carry means addition complete
int val1 = l1 ? l1->val : 0;Use 0 if l1 is exhausted to handle different lengths
int total = val1 + val2 + carry;Sum current digits and carry
ListNode* node = new ListNode(total % 10);Create node for current digit
node->next = addTwoNumbersRecursive(next1, next2, carry);Recursive call for next digits and carry
return node;Return current node to link with previous
function ListNode(val, next = null) {
this.val = val;
this.next = next;
}
function addTwoNumbersRecursive(l1, l2, carry = 0) {
if (l1 === null && l2 === null && carry === 0) return null;
let val1 = l1 !== null ? l1.val : 0;
let val2 = l2 !== null ? l2.val : 0;
let total = val1 + val2 + carry;
carry = Math.floor(total / 10);
let node = new ListNode(total % 10);
let next1 = l1 !== null ? l1.next : null;
let next2 = l2 !== null ? l2.next : null;
node.next = addTwoNumbersRecursive(next1, next2, carry);
return node;
}
// Driver code
function createList(arr) {
let dummy = new ListNode(0);
let cur = dummy;
for (let num of arr) {
cur.next = new ListNode(num);
cur = cur.next;
}
return dummy.next;
}
let l1 = createList([2,4,3]);
let l2 = createList([5,6,4]);
let result = addTwoNumbersRecursive(l1, l2);
while (result !== null) {
process.stdout.write(result.val + ' ');
result = result.next;
}
console.log();
Line Notes
if (l1 === null && l2 === null && carry === 0) return null;Base case: no nodes and no carry means addition complete
let val1 = l1 !== null ? l1.val : 0;Use 0 if l1 is exhausted to handle different lengths
let total = val1 + val2 + carry;Sum current digits and carry
let node = new ListNode(total % 10);Create node for current digit
node.next = addTwoNumbersRecursive(next1, next2, carry);Recursive call for next digits and carry
return node;Return current node to link with previous
TimeO(max(m, n))
SpaceO(max(m, n)) due to recursion stack
Each node is processed once, but recursion adds stack overhead proportional to the longer list length.
💡 For very long lists (e.g., 10^5 nodes), recursion may cause stack overflow, so iterative is safer.
Interview Verdict: Accepted but less practical for large inputs
While elegant, recursion risks stack overflow and is less preferred in interviews for large inputs.