The O(n) Club: Sort List—Where Linked Lists and Merge Sort Go Full Buddy Cop

The O(n) Club: Sort List—Where Linked Lists and Merge Sort Go Full Buddy Cop

⚡ TL;DR

LeetCode 148 wants you to sort a singly linked list. Brute force is like taking a detour via ArrayLand: copy to array, sort, rebuild the list, and hope no pointer gets homesick. The elegant answer? Merge sort—divide-and-conquer so slick, your list barely breaks a sweat.

// Brute-ish way (it works, but so does eating ramen every night)
List<Integer> temp = new ArrayList<>();
while (head != null) {
    temp.add(head.val);
    head = head.next;
}
Collections.sort(temp);
// Rebuild node-by-node...

🧠 How Devs Usually Mess This Up

Instinct says, “Arrays are easy! Let’s treat linked lists like arrays.” Nope. Try porting quicksort or heapsort over, and your runtime will blow up like a caffeine-fueled DevOps fire drill. Linked lists hate you poking into their guts by index—no instant teleporting to the 1000th node here! Swapping pointers in place? That’s like wrestling an octopus while blindfolded. End result: code that makes you wish you’d just become a barista instead.

🔍 What’s Actually Going On

Merge sort was made for this. Instead of cramming everything into an array, we use the fast and slow pointer technique (imagine a tortoise and hare racing) to split the list cleanly in half. Then, recursively sort both sides like a lazy chef prepping two dishes at once, and finally stitch them together with zero extra containers—just a trusty dummy node as sous-chef. Sequential merging means no wild pointer acrobatics, and we keep space usage leaner than a JavaScript build with tree shaking.

🛠️ PseudoCode

  • Base Case: If list is empty or single node, it’s already sorted—champagne!
    if (head == null || head.next == null) return head;
  • Find the Middle: Use fast and slow pointers so you don’t trip over indexes.
    ListNode slow = head, fast = head.next;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    ListNode mid = slow.next;
    slow.next = null; // Split
  • Sort Recursively:
    ListNode left = sortList(head);
    ListNode right = sortList(mid);
  • Merge Two Sorted Halves:
    return merge(left, right);

    Dummy saver node for super clean pointer juggling.

💻 The Code

// Definition for singly-linked list:
class ListNode {
    int val;
    ListNode next;
    ListNode(int val) { this.val = val; }
}
 public ListNode sortList(ListNode head) {
    if (head == null || head.next == null) return head;
    // Find the mid-point
    ListNode slow = head, fast = head.next;
    while (fast != null && fast.next != null) {
        slow = slow.next;
        fast = fast.next.next;
    }
    ListNode mid = slow.next;
    slow.next = null;
    // Sort halves
    ListNode left = sortList(head);
    ListNode right = sortList(mid);
    // Merge
    return merge(left, right);
}
 private ListNode merge(ListNode l1, ListNode l2) {
    ListNode dummy = new ListNode(0);
    ListNode tail = dummy;
    while (l1 != null && l2 != null) {
        if (l1.val < l2.val) {
            tail.next = l1;
            l1 = l1.next;
        } else {
            tail.next = l2;
            l2 = l2.next;
        }
        tail = tail.next;
    }
    tail.next = (l1 != null) ? l1 : l2;
    return dummy.next;
}

⚠️ Pitfalls, Traps & Runtime Smacks

  • Splitting Slip-ups: Forgetting to break the list—hello, infinite cycles or list spaghetti.
  • Pointer Pandemonium: Off-by-one errors in mid-point logic. Always test on lists with both odd and even numbers of nodes.
  • Accidentally Allocating New Nodes: If you’re not careful, you’ll burn more memory than a memory leak demo. Keep it in-place—relink, don’t rebuild.
  • Stack Attack: Deep recursion and big lists can explode the call stack. If LeetCode explodes, you need iterative merge sort (bring aspirin).
  • Complexity: O(n log n) time, O(1) extra space (excluding recursion). Any slower, and you’re doing community service for inefficient code.

🧠 Interviewer Brain-Tattoo

“Sorting a linked list with quicksort is like using chopsticks to eat soup. Merge sort just brings the bowl.”

Previous Article

The O(n) Club: House Robber III: Binary Trees, Burglaries & Existential Dread

Next Article

The O(n) Club: Binary Tree Right Side View: Why Only ‘Right’ Isn’t Always Right