Day 07/90: Adding Two Numbers Represented by Linked Lists in TypeScript/JavaScript
Introduction When numbers are represented as linked lists where each digit is stored in reverse order, adding them requires careful traversal and carry management. Today, we'll solve LeetCode Problem 2 ("Add Two Numbers") efficiently in TypeScript/JavaScript. The Problem Given two non-empty linked lists representing two non-negative integers (with digits stored in reverse order), add the two numbers and return the sum as a linked list. Example: Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = 807 The Optimal Solution function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null { let dummy = new ListNode(0); let current = dummy; let carry = 0; while (l1 || l2 || carry) { const x = l1 ? l1.val : 0; const y = l2 ? l2.val : 0; const sum = x + y + carry; carry = Math.floor(sum / 10); current.next = new ListNode(sum % 10); current = current.next; if (l1) l1 = l1.next; if (l2) l2 = l2.next; } return dummy.next; }; This solution is: ✅ Efficient - O(max(n,m)) time complexity ✅ Clean - Handles all cases uniformly ✅ Memory-friendly - O(max(n,m)) space complexity How It Works Dummy Node: Simplifies edge cases by providing an initial node Carry Propagation: Tracks overflow between digit places Flexible While Condition: Continues until both lists and carry are exhausted Null Handling: Safely accesses values using ternary operators Alternative Approaches Recursive Solution function addTwoNumbers(l1: ListNode | null, l2: ListNode | null, carry = 0): ListNode | null { if (!l1 && !l2 && !carry) return null; const sum = (l1?.val || 0) + (l2?.val || 0) + carry; return new ListNode( sum % 10, addTwoNumbers(l1?.next || null, l2?.next || null, Math.floor(sum / 10)) ); } Pros: More declarative style No dummy node needed Cons: Potential stack overflow for very long lists Slightly less efficient Convert-and-Add Approach: function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null { const num1 = listToNum(l1); const num2 = listToNum(l2); return numToList(num1 + num2); } function listToNum(node: ListNode | null): number { let num = 0; let place = 1; while (node) { num += node.val * place; place *= 10; node = node.next; } return num; } function numToList(num: number): ListNode | null { if (num === 0) return new ListNode(0); let dummy = new ListNode(0); let current = dummy; while (num > 0) { current.next = new ListNode(num % 10); current = current.next; num = Math.floor(num / 10); } return dummy.next; } Pros: Conceptually simple Easy to understand Cons: Fails with very large numbers (JavaScript number precision limits) Inefficient for long lists Edge Cases to Consider Lists of different lengths Final carry (e.g., 5 + 5 = 10) Zero values Single-digit lists Large numbers (but within JavaScript safe integer range) Performance Considerations The optimal solution: Processes each node exactly once Uses constant extra space (just the carry) Minimizes memory allocations Conclusion The dummy node approach provides the best combination of:

Introduction
When numbers are represented as linked lists where each digit is stored in reverse order, adding them requires careful traversal and carry management. Today, we'll solve LeetCode Problem 2 ("Add Two Numbers") efficiently in TypeScript/JavaScript.
The Problem
Given two non-empty linked lists representing two non-negative integers (with digits stored in reverse order), add the two numbers and return the sum as a linked list.
Example:
Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
Output: 7 -> 0 -> 8
Explanation: 342 + 465 = 807
The Optimal Solution
function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null {
let dummy = new ListNode(0);
let current = dummy;
let carry = 0;
while (l1 || l2 || carry) {
const x = l1 ? l1.val : 0;
const y = l2 ? l2.val : 0;
const sum = x + y + carry;
carry = Math.floor(sum / 10);
current.next = new ListNode(sum % 10);
current = current.next;
if (l1) l1 = l1.next;
if (l2) l2 = l2.next;
}
return dummy.next;
};
This solution is:
✅ Efficient - O(max(n,m)) time complexity
✅ Clean - Handles all cases uniformly
✅ Memory-friendly - O(max(n,m)) space complexity
How It Works
Dummy Node: Simplifies edge cases by providing an initial node
Carry Propagation: Tracks overflow between digit places
Flexible While Condition: Continues until both lists and carry are exhausted
Null Handling: Safely accesses values using ternary operators
Alternative Approaches
- Recursive Solution
function addTwoNumbers(l1: ListNode | null, l2: ListNode | null, carry = 0): ListNode | null {
if (!l1 && !l2 && !carry) return null;
const sum = (l1?.val || 0) + (l2?.val || 0) + carry;
return new ListNode(
sum % 10,
addTwoNumbers(l1?.next || null, l2?.next || null, Math.floor(sum / 10))
);
}
Pros:
More declarative style
No dummy node needed
Cons:
Potential stack overflow for very long lists
Slightly less efficient
- Convert-and-Add Approach:
function addTwoNumbers(l1: ListNode | null, l2: ListNode | null): ListNode | null {
const num1 = listToNum(l1);
const num2 = listToNum(l2);
return numToList(num1 + num2);
}
function listToNum(node: ListNode | null): number {
let num = 0;
let place = 1;
while (node) {
num += node.val * place;
place *= 10;
node = node.next;
}
return num;
}
function numToList(num: number): ListNode | null {
if (num === 0) return new ListNode(0);
let dummy = new ListNode(0);
let current = dummy;
while (num > 0) {
current.next = new ListNode(num % 10);
current = current.next;
num = Math.floor(num / 10);
}
return dummy.next;
}
Pros:
Conceptually simple
Easy to understand
Cons:
Fails with very large numbers (JavaScript number precision limits)
Inefficient for long lists
Edge Cases to Consider
Lists of different lengths
Final carry (e.g., 5 + 5 = 10)
Zero values
Single-digit lists
Large numbers (but within JavaScript safe integer range)
Performance Considerations
The optimal solution:
Processes each node exactly once
Uses constant extra space (just the carry)
Minimizes memory allocations
Conclusion
The dummy node approach provides the best combination of: