DSALinear Patterns (1D)Linked List Manipulation

Linked List Manipulation

Linear Patterns (1D)

Why do we use a linked list, say over an array? Their true power comes from the ability to manipulate pointers. You can break, reconnect, and reorder nodes in a way that is not possible with static structures like arrays. Inorder to solve linked list problems, you must learn the art of re-wiring a list as required.

Here is a problem to test of your linked list skills. It can be broken down into several smaller, fundamental patterns. Try to map out the steps on paper before looking ahead.

Problem: Reorder List LeetCode Link : Given a linked list, reorder it in a specific way: L0 → Ln → L1 → Ln-1 → L2 → Ln-2 → ... 💡 Hint

To solve this challenge, you need to apply a series of transformations on the linked list.

1. Finding the Middle (Fast & Slow Pointers)

If you haven't already read the Tortoise and Hare chapter, please do so now. The chapter talks about using fast and slow pointers on arrays, but the same principle applies to linked lists.

2. In-Place List Reversal

This is one of the fundamental linked list manipulation patterns. The idea is to maintain 3 pointers while traversing the list: prev, curr, and next. In each iteration you will update the next pointer of curr to point to prev, effectively reversing the direction of the link.

10
20
30
40
prev
curr
next
def reverse_list(head):
    prev = None
    curr = head
    while curr:
        next = curr.next  # Store next node
        curr.next = prev       # Reverse the link
        prev = curr            # Move prev to current
        curr = next       # Move to next node
    return prev  # New head of the reversed list

3. Merging Two Lists

This involves creating a new list by picking nodes from two other lists. You typically maintain a pointer to the head of each list and a tail pointer for the new merged list. At each step, you decide which node to append to the tail and advance its corresponding pointer.

Pro tip: This same idea is used in k-way merging problems, where you merge multiple sorted lists into one. Always pick the smallest node from the heads of the lists and append it to the merged list. Use a min-heap for efficiency when merging k lists.

Walkthrough: Solving "Reorder List"

Now, let's solve our challenge by combining our three tools in a clear, three-step process:

  1. Find the middle of the list: Use the Fast & Slow Pointer pattern to find the start of the second half of the list.
  2. Reverse the second half: We take the second half of the list (starting from the middle node) and apply the In-Place List Reversal pattern to it. Now we have two distinct lists: the first half and the reversed second half.
  3. Merge the two halves: We "weave" the two lists together. We take the first node from the first half, then the first node from the second half, then the second node from the first half, and so on, carefully re-wiring their next pointers until the second list is exhausted.
def reorder_list(head):
    if not head or not head.next:
        return

    # Step 1: Find the middle of the list
    slow, fast = head, head
    while fast.next and fast.next.next:
        slow = slow.next
        fast = fast.next.next

    # Step 2: Reverse the second half of the list
    second_half_head = slow.next
    slow.next = None  # Split the list
    
    prev = None
    curr = second_half_head
    while curr:
        next_node = curr.next
        curr.next = prev
        prev = curr
        curr = next_node
    second = prev # `prev` is now the head of the reversed second half

    # Step 3: Merge the two halves
    first = head
    while second:
        temp1, temp2 = first.next, second.next
        first.next = second
        second.next = temp1
        first, second = temp1, temp2

Complexity Analysis

Time Complexity: O(N)O(N) Finding the middle is O(N)O(N). Reversing the second half is O(N/2)O(N/2), which is still O(N)O(N). Merging the two halves is another O(N)O(N). Overall, the complexity is linear.

Space Complexity: O(1)O(1) Because we are manipulating the list "in-place," we only use a few extra pointers, resulting in constant extra space.

More Problems & Variations

Now that you have the core toolkit, you can apply these building blocks to solve a wide range of other problems.

  • Reverse Linked List II LeetCode 💡 Hint
  • Palindrome Linked List LeetCode 💡 Hint
  • Merge Two Sorted Lists LeetCode 💡 Hint
  • Merge k Sorted Lists LeetCode 💡 Hint
  • Remove Nth Node From End of List LeetCode 💡 Hint 💡 Hint
  • Copy List with Random Pointer LeetCode 💡 Hint