Two numbers are stored as reversed-digit linked lists. Walk both simultaneously, tracking a carry at each position and appending result nodes via a dummy head — the same pattern as grade-school long addition.
You are given two non-empty linked lists representing non-negative integers. The digits are stored in reverse order (least-significant digit first) and each node holds a single digit. Add the two numbers and return the sum as a linked list in the same reversed format.
Concrete example: l1 = [2,4,3] represents 342; l2 = [5,6,4] represents 465. Their sum is 807, so the answer is [7,0,8].
dummy head node lets you append without special-casing the first node.dummy = new ListNode(0) and point curat it. This eliminates the “first node is special” edge case — you always do cur.next = ….l1, l2, or carry is non-zero. The carry condition handles the final digit when one number is longer (e.g., 999 + 1 = 1000).l1?.val ?? 0 — an exhausted list contributes 0, not an error.sum = d1 + d2 + carry. Append new ListNode(sum % 10) and set carry = Math.floor(sum / 10).cur, and advance l1/l2only if they're not null.|| carry !== 0 in the loop condition. If both lists are exhausted but carry is still 1 (e.g., 5 + 5 = 10), the loop exits too early and the leading 1 is never appended. Always keep carry in the while condition.Space: O(max(m, n) + 1) for the result list. The +1 is for a possible carry node at the end (e.g., 5 + 5 produces [0, 1]). No stack or auxiliary data structure needed.
2→4→3 and 5→6→4 digit by digit (LSB first). Carry starts at 0. cur points to the dummy sentinel.1// Definition for singly-linked list.2class ListNode {3 val: number;4 next: ListNode | null;5 constructor(val = 0, next: ListNode | null = null) {6 this.val = val;7 this.next = next;8 }9}1011function addTwoNumbers(12 l1: ListNode | null,13 l2: ListNode | null14): ListNode | null {15▶ const dummy = new ListNode(0); // sentinel head — avoids edge-case for first node16▶ let cur = dummy;17▶ let carry = 0;1819 while (l1 !== null || l2 !== null || carry !== 0) {20 const d1 = l1?.val ?? 0; // treat an exhausted list as supplying 021 const d2 = l2?.val ?? 0;22 const sum = d1 + d2 + carry;2324 cur.next = new ListNode(sum % 10); // append the ones digit25 carry = Math.floor(sum / 10); // propagate the tens digit2627 cur = cur.next;28 if (l1) l1 = l1.next;29 if (l2) l2 = l2.next;30 }3132 return dummy.next; // skip the sentinel33}
// Definition for singly-linked list.
class ListNode {
val: number;
next: ListNode | null;
constructor(val = 0, next: ListNode | null = null) {
this.val = val;
this.next = next;
}
}
function addTwoNumbers(
l1: ListNode | null,
l2: ListNode | null
): ListNode | null {
const dummy = new ListNode(0); // sentinel head — avoids edge-case for first node
let cur = dummy;
let carry = 0;
while (l1 !== null || l2 !== null || carry !== 0) {
const d1 = l1?.val ?? 0; // treat an exhausted list as supplying 0
const d2 = l2?.val ?? 0;
const sum = d1 + d2 + carry;
cur.next = new ListNode(sum % 10); // append the ones digit
carry = Math.floor(sum / 10); // propagate the tens digit
cur = cur.next;
if (l1) l1 = l1.next;
if (l2) l2 = l2.next;
}
return dummy.next; // skip the sentinel
}dummy = new ListNode(0) and pointing cur at it means the first real node is created the same way as every subsequent one: cur.next = new ListNode(...). No branch needed for “is this the head?”l1 !== null, l2 !== null, or carry !== 0. The carry clause is the one people forget — it handles the final overflow digit (e.g., 999 + 1 = 1000).?? 0 idiom means an exhausted pointer silently contributes zero rather than requiring an if/else. The sum is always valid regardless of whether one list is shorter.sum % 10 is the ones digit; Math.floor(sum / 10) is the carry (always 0 or 1 since max sum per column is 9 + 9 + 1 = 19). Appending directly to cur.next keeps the pointer management simple.cur. Advance l1/l2 only when not null — the loop condition already handles the case where one list is exhausted.dummy itself was the placeholder; the first real result digit is at dummy.next.parseInt.[5]+[5]=[0,1]), single-node lists, and one list being all 9s.| two numbers as reversed linked lists | single while loop + carry |
| build a new linked list node by node | dummy head sentinel |
| digit-by-digit addition with overflow | sum % 10 + Math.floor(sum / 10) |
| lists may have different lengths | optional-chaining ?? 0 for exhausted ptr |
const dummy = new ListNode(0);
let cur = dummy;
let carry = 0;
while (l1 !== null || l2 !== null || carry !== 0) {
const d1 = l1?.val ?? 0;
const d2 = l2?.val ?? 0;
const sum = d1 + d2 + carry;
cur.next = new ListNode(sum % 10);
carry = Math.floor(sum / 10);
cur = cur.next;
if (l1) l1 = l1.next;
if (l2) l2 = l2.next;
}
return dummy.next;cur.next = new ListNode(…) — no special case for the first result node.l1 = [2,4,3] and l2 = [5,6,4], what does the function return?|| carry !== 0?return dummy.next rather than return dummy?l1 = [9,9,9], l2 = [1]. What is the output?l1?.val ?? 0 return when l1 is null?