Algorithm

Merge Two Sorted Lists

Two Pointer Pattern

Merge Two Sorted Lists

Given the heads of two linked lists that are each already sorted in non-decreasing order, splice them into one sorted linked list and return its head. Build the result by relinking the existing nodes (do not allocate new ones). Either list may be empty; if both are empty, return null (an empty list).

CONSTRAINTS
  • 0 to 50 nodes per list
  • -100 <= Node.val <= 100
  • Both input lists are already sorted in non-decreasing order
EXAMPLE 1
Input: list1 = [1,2,4], list2 = [1,3,4]
Output: [1,1,2,3,4,4]
Reading the two sorted lists together and always taking the smaller front value produces one sorted sequence.
EXAMPLE 2
Input: list1 = [], list2 = [0]
Output: [0]
One list is empty, so the result is just the other list unchanged.
EXAMPLE 3
Input: list1 = [], list2 = []
Output: []
Both lists are empty, so there is nothing to merge.
Should I create new nodes or reuse the existing ones?
Reuse the existing nodes by relinking their .next pointers. No new nodes are needed.
What if one or both lists are empty?
If one is empty, return the other. If both are empty, return null.
How are ties (equal values) handled?
Take either one; taking from the first list on a tie keeps the merge stable, which is the conventional choice.

We are handed two lists that are already sorted, and we want one sorted list out. The fact that they are pre-sorted is the whole gift — it means we never have to sort anything.

The wasteful way that ignores the sorting

You could pour every value into an array, sort it, and build a fresh list. That is O((N+M) log(N+M)) time for a sort we did not need, plus O(N+M) space for a brand-new list — when the answer is just the same nodes in a new order.

python
vals = []
while l1: vals.append(l1.val); l1 = l1.next
while l2: vals.append(l2.val); l2 = l2.next
vals.sort()
dummy = tail = Node(0)
for v in vals:
    tail.next = Node(v); tail = tail.next
return dummy.next
One pointer on each list, always take the smaller head

Here is a new twist on two pointers: instead of two markers walking the same array, we put one marker on each list and walk them forward independently. (You saw a first taste of this in Is Subsequence, where two pointers crawled two different strings.) The key fact: because both lists are sorted, the smallest value not yet placed is always sitting at the head of one list or the other — it can't be hiding deeper in, because everything behind a head is larger. So we just compare the two current heads, take the smaller one, and advance that list's pointer. Repeat, and the output comes out sorted.

python
dummy = tail = Node(0)          # dummy avoids special-casing the first node
while l1 and l2:
    if l1.val <= l2.val:
        tail.next = l1          # smaller head joins the result
        l1 = l1.next
    else:
        tail.next = l2
        l2 = l2.next
    tail = tail.next
tail.next = l1 or l2            # one list is empty; attach whatever remains
return dummy.next

Two small but important pieces. The dummy node is a throwaway node we hang the result off of, so we never need an if to handle "is this the very first node?" — we just return dummy.next at the end. And the last line, tail.next = l1 or l2: once one list runs dry, the other's remaining nodes are already sorted and already larger than everything placed, so we splice the whole tail on in one move instead of comparing node by node.

Crucial Notecomparing with <= (not <) keeps the merge stable — when the two heads tie, taking l1 first preserves the original relative order. It doesn't change correctness here, but the habit matters in sorts where equal keys carry other data.
Worked example:l1 = 1 → 2 → 4, l2 = 1 → 3 → 4
- Heads 1 and 1 tie → take l1's 1. l1 → 2.
- Heads 2 and 1 → take l2's 1. l2 → 3.
- Heads 2 and 3 → take 2. l1 → 4.
- Heads 4 and 3 → take 3. l2 → 4.
- Heads 4 and 4 → take l1's 4. l1 runs out.
- Attach the rest of l2 (4). Result: 1 → 1 → 2 → 3 → 4 → 4.
The specialty: two pointers across two sequences

This is the third shape of the two-pointer pattern. The same-direction form walked one array with a fast and slow pointer; the converging form walked one array from both ends; this multiple-sequence form runs a pointer through each of two (or more) separate sequences at once. The reusable skeleton has three slots: (a) compare the current fronts of the sequences, (b) decide which sequence to take from and advance, (c) decide what to emit. Fill them differently and you get different problems — here (a) compare heads, (b) advance the smaller, (c) emit that node. It only works because each sequence is sorted, so its smallest remaining item is always at its front. This exact merge is the "combine" step of merge sort, and scaling it from two lists to many is the next problem, Merge k Sorted Lists. Recognition signal: whenever you must combine or compare two already-sorted sequences in order, reach for one pointer per sequence and advance whichever front loses the comparison.

Interactive Strategy Visualization
MERGE HARMONIZER

Iterative Two-Pointer Sync

List 1 (L1)
1
2
4
List 2 (L2)
1
3
4
Unified Sorted Result

Current Focus

Phase 1: Dual Sentinel Entry

We use a Dummy Node as our anchor. Pointers L1 and L2 stand at the gates of our two sorted streams.

Efficiency Note

We reuse existing node pointers. No new nodes are created (except the dummy), making this an **O(1) extra space** operation.

Strategy: Tail Appending

By comparing nodes one by one and appending the smaller to the new tail, we build the final list in a single pass of O(N + M).

O((N+M) log(N+M)) Collect & Sort
O(N + M) Time · O(1) Space Two-Pointer Merge