Flatten a Linked List takes a list whose nodes each hang their own sorted sub-list and folds everything into a single sorted list. It is the classic way to practice the merge step of merge sort on linked structures, where you splice pointers instead of copying values.
Problem. You are given a linked list where each node has two pointers: next (to the next head,
left to right) and bottom (down into a sorted sub-list). Flatten it into one sorted list linked
only by bottom, and return its head.
Example: heads 5 → 2 → 1, where the bottom lists are 5 → 7, 2 → 6, and 1 → 4 → 8.
Flattened result: 1 → 2 → 4 → 5 → 6 → 7 → 8.
The slow way first
The blunt approach: collect every value into an array, sort it, then rebuild a fresh bottom-linked list. That works, but sorting throws away a gift the input already hands us — each column is already sorted. Re-sorting n values costs O(n log n) and ignores the structure entirely.
The question to ask: if every piece is already sorted, how do I combine sorted pieces without re-sorting? You merge them, exactly like merge sort's combine step.
The idea: merge columns right to left
Treat each column (a head and its bottom list) as one sorted list. Recurse along next to the rightmost head first — that column, having no next, is already a flat sorted list and becomes the base. Then walk back leftward, and at each head merge its column into the accumulated flattened list. Two sorted bottom-lists merge by repeatedly taking the smaller front node and splicing it onto the result.
The key insight: because both lists going into each merge are already sorted, one linear pass interleaves them. Folding columns in one at a time keeps the running result sorted the whole way.
Walk through it
Step through the animation. We first recurse to the last column 1 → 4 → 8 and seed the result with it. Then we step left and merge 2 → 6 into it, slotting 2 and 6 into place. Finally we merge 5 → 7, and every value lands in its sorted slot, producing one bottom-linked list 1 → 2 → 4 → 5 → 6 → 7 → 8.
Pseudocode
flatten(head):
if head is empty or has no next column:
return head # single sorted column = done
head.next = flatten(head.next) # flatten everything to the right first
head = merge(head, head.next) # fold this column into that result
return head
merge(a, b): # both lists are sorted by bottom
walk a and b together, always taking the smaller front node
link it onto the result via bottom
when one runs out, attach the remainder of the other
return the merged headThe Python solution
def flatten(head):
if head is None or head.next is None:
return head
head.next = flatten(head.next)
head = merge(head, head.next)
return head
def merge(a, b):
dummy = tail = Node(0)
while a and b:
if a.val <= b.val:
tail.bottom, a = a, a.bottom
else:
tail.bottom, b = b, b.bottom
tail = tail.bottom
tail.bottom = a or b
return dummy.bottom- The base case in line 2 stops the recursion at the rightmost column — a single sorted list needs no merging.
- Line 4 flattens everything to the right of the current head before touching the current column, so
mergealways receives two already-sorted lists. - Line 5 merges the current column into that flattened remainder; the result becomes the new head.
- In
merge, thedummynode lets us build the result without special-casing the first link;tailalways points at the last placed node. - Each loop turn compares the two front values and splices the smaller one onto
tail.bottom, then advances that list. When one list empties, line 16 attaches the rest of the other in one move.
Complexity
| Case | Time | Notes |
|---|---|---|
| Collect, sort, rebuild | O(n log n) (moderate) | throws away the sorted structure |
| Merge columns (this solution) | O(n · k) (moderate) | each value passes through merges |
O(k) (moderate)Here n is the total number of nodes and k is the number of columns. Each value is touched once per merge it participates in, so the work is O(n · k) in the splicing approach (often written O(n²) when columns are comparable in size). The extra space is just the O(k) recursion depth — we splice existing nodes rather than copying them.
When this pattern shows up
Whenever you must combine several already-sorted sequences, reach for merging rather than a fresh sort. "Merge two sorted lists," "merge k sorted lists," and this flatten problem are the same move: repeatedly take the smallest available front element and splice it onto the result.
Flatten with bottom, not next. The final list must be linked through bottom pointers; leaving
stray next links is the most common bug. A dummy head in merge also saves you from special-casing
whether the first node comes from list a or list b.
Practice
We merge right to left. After seeding the result with the last column 1 → 4 → 8 and then merging 2 → 6, what is the running result before the first column is merged?
1. Why do we merge instead of collecting all values and sorting them?
2. Why does the recursion flatten head.next before merging the current column?
3. What is the role of the dummy node in merge?
4. Which pointer must link the final flattened list?