When a coding interview asks you to "reorder a list", "remove duplicates", or "reverse a segment", it is usually hinting at the linked‑list manipulation pattern. The core idea is simple: you walk the list once, adjusting the next pointers of the nodes you touch, and you never allocate new nodes unless the problem explicitly permits it. Below we break down the pattern, show a worked example in Python, discuss complexity and pitfalls, and give you five practice problems to master the technique.

Spotting the Pattern

Signal in the PromptWhat It Means
"in‑place" or "without extra space"You must change the existing links, not create a new list.
"reorder", "rotate", "reverse"You’ll be moving pointers around rather than sorting values.
"remove/insert nodes"Direct pointer manipulation is required.
"single/double linked list"Choose the appropriate traversal (forward only for singly linked, both directions for doubly).

If you see any of these phrases, pause and think about how you would walk the list and modify the next references.

Core Steps of the Pattern

  1. Identify the traversal direction – For singly linked lists you can only move forward, so you often need a prev pointer or a dummy head.
  2. Create stable anchors – A dummy node (dummy = ListNode(0)) protects you from losing the head when you splice nodes.
  3. Iterate with clear invariants – Keep track of what part of the list is already processed and what remains.
  4. Update pointers – Change node.next to point where you need; be careful to store the next node before you overwrite a link.
  5. Return the new head – Usually dummy.next.

Worked Example: Remove Duplicates from a Sorted List

Problem: Given the head of a sorted singly linked list, delete all nodes that have duplicate values, leaving only distinct numbers.

class ListNode:
    def __init__(self, val=0, next=None):
        self.val = val
        self.next = next

def delete_duplicates(head: ListNode) -> ListNode:
    dummy = ListNode(0, head)   # anchor before the real head
    prev = dummy                # last node known to be unique
    cur = head
    while cur:
        # Detect a run of equal values
        if cur.next and cur.val == cur.next.val:
            dup_val = cur.val
            # Skip all nodes with this value
            while cur and cur.val == dup_val:
                cur = cur.next
            prev.next = cur      # splice out the duplicates
        else:
            prev = cur           # current node is unique
            cur = cur.next
    return dummy.next

Complexity: The algorithm visits each node at most twice, so time is O(n). Only a few pointers are stored, giving O(1) extra space.

Why it works: The dummy node guarantees we have a stable predecessor (prev) even when the first few nodes are duplicates. The inner while loop skips the whole block of equal values, preventing us from accidentally linking to a duplicate later.

Common Pitfalls

  • Losing the rest of the list – Overwriting node.next before saving next_node is a classic bug.
  • Incorrect dummy handling – Forgetting to return dummy.next leads to returning the placeholder node.
  • Assuming the list is sorted – Many solutions rely on sorting; if the prompt says "unsorted", you need a hash set or a two‑pass approach.
  • Off‑by‑one in loops – When reversing a segment, be careful with the boundaries; use inclusive/exclusive conventions consistently.

Five Representative Practice Problems

  1. Reverse a Sub‑list – Given m and n, reverse the nodes from position m to n. Hint: Use three pointers (prev, curr, next) and reverse links in‑place inside the window.
  2. Detect and Remove Cycle – Find the start of a cycle (Floyd’s algorithm) and break it. Hint: After detection, keep a pointer at the head and move both pointers one step until they meet; set the predecessor’s next to None.
  3. Merge Two Sorted Lists – Combine two sorted singly linked lists into one sorted list. Hint: Use a dummy head and always attach the smaller node, advancing that list’s pointer.
  4. Partition List Around a Value – Rearrange nodes so that all nodes less than x come before nodes greater or equal, preserving original order. Hint: Build two dummy lists (less and greater) and concatenate them.
  5. Copy List with Random Pointer – Each node has an extra random pointer; create a deep copy without extra O(n) space. Hint: Interleave copied nodes between originals, then separate them.

These problems cover reversal, cycle handling, merging, partitioning, and a more advanced pointer‑copy scenario. Working through them will expose you to the full range of pointer gymnastics interviewers love.

How to Practice This

  1. Timed runs – Set a 15‑minute timer, read the problem, and code a solution without looking at references.
  2. Explain aloud – Use Call Assistant to rehearse your answer; speaking forces you to articulate each pointer change clearly.
  3. Walk through edge cases – After coding, manually trace the algorithm on an empty list, a single‑node list, and a list where every node needs to be changed.

FAQ

  • Q: Do I always need a dummy node? A: Not always, but a dummy simplifies handling head changes and eliminates special‑case code for the first node.
  • Q: Can I use recursion for linked‑list manipulation? A: Recursion works for some tasks (e.g., reversal) but risks stack overflow on long lists; iterative solutions are usually preferred in interviews.
  • Q: How do I debug pointer bugs quickly? A: Print the list after each major step, or use a visualizer that shows node addresses and next links.
  • Q: When is extra space acceptable? A: If the prompt explicitly allows O(n) space (e.g., copying with a hash map) or if it simplifies the solution without hurting performance.

Frequently asked questions

When should I choose a linked‑list solution over an array solution?

If the problem mentions in‑place reordering, node insertion/deletion, or requires O(1) extra space, a linked list is usually the intended structure. Arrays force you to shift elements, which is O(n) per operation.

What’s the safest way to handle the head pointer when nodes are removed?

Introduce a dummy node before the real head. It gives you a stable predecessor (`prev`) even when the first few nodes are deleted, letting you return `dummy.next` at the end.

How can I avoid losing the rest of the list during pointer updates?

Always store `next_node = cur.next` before you modify `cur.next`. Then you can safely rewire the current node and continue traversal using `next_node`.

Is it okay to use Python’s list type to simulate a linked list?

For practice it can help visualize data, but interviewers expect you to work with a `ListNode` class and explicit `next` pointers, showing you understand pointer manipulation.

#coding pattern#linked list manipulation#interview prep#python#algorithm