Reorder Linked List in DSA Go - Time & Space Complexity
We want to understand how the time needed changes when we reorder a linked list.
Specifically, how the steps grow as the list gets longer.
Analyze the time complexity of the following code snippet.
func reorderList(head *ListNode) {
if head == nil || head.Next == nil {
return
}
// Find middle
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
// Reverse second half
var prev *ListNode
curr := slow.Next
slow.Next = nil
for curr != nil {
nextTemp := curr.Next
curr.Next = prev
prev = curr
curr = nextTemp
}
// Merge two halves
first, second := head, prev
for second != nil {
tmp1 := first.Next
tmp2 := second.Next
first.Next = second
second.Next = tmp1
first = tmp1
second = tmp2
}
}
This code reorders a linked list by first finding the middle, reversing the second half, then merging the two halves.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: Three loops: one to find the middle, one to reverse the second half, and one to merge two halves.
- How many times: Each loop runs roughly n/2 times where n is the list length.
As the list size grows, each of the three loops grows linearly with the list length.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 30 steps (3 loops x ~5 steps each) |
| 100 | About 150 steps (3 loops x ~50 steps each) |
| 1000 | About 1500 steps (3 loops x ~500 steps each) |
Pattern observation: The total steps increase roughly in direct proportion to the list size.
Time Complexity: O(n)
This means the time needed grows directly with the number of nodes in the list.
[X] Wrong: "Reversing the second half or merging halves takes more than linear time because of nested loops."
[OK] Correct: Each loop runs separately and only once over part of the list, so they add up linearly, not multiply.
Understanding this linear time complexity helps you explain efficient list manipulation clearly and confidently in interviews.
"What if we used recursion to reverse the second half instead of a loop? How would the time complexity change?"
Practice
Reorder Linked List problem?Solution
Step 1: Understand the problem statement
The problem asks to reorder the list so that nodes come alternately from the start and the end, like L0 -> Ln -> L1 -> Ln-1 -> L2 -> Ln-2 and so on.Step 2: Differentiate from other operations
This is not sorting or reversing the entire list, but a specific pattern of rearrangement.Final Answer:
Rearrange the list so nodes alternate from start and end towards the center -> Option AQuick Check:
Reorder = alternate start/end nodes [OK]
- Confusing reorder with sorting
- Trying to reverse the whole list only
- Ignoring the alternating pattern
Solution
Step 1: Identify Go struct syntax
In Go, structs are declared with the keywordtype, fields have names and types separated by spaces, and pointers use*.Step 2: Match correct field names and types
type ListNode struct { Val int; Next *ListNode } usesVal intandNext *ListNode, which is the standard for singly linked list nodes in Go.Final Answer:
type ListNode struct { Val int; Next *ListNode } -> Option BQuick Check:
Go struct with pointer field = type ListNode struct { Val int; Next *ListNode } [OK]
- Using C/C++ or Java syntax in Go
- Missing pointer * for next node
- Incorrect field names or types
Solution
Step 1: Identify the reorder pattern
The reorder pattern takes the first node, then the last node, then second node, then second last node, and so on.Step 2: Apply pattern to given list
Start: 1, end: 5, then 2, then 4, then 3 in the middle. So the reordered list is 1 -> 5 -> 2 -> 4 -> 3 -> null.Final Answer:
1 -> 5 -> 2 -> 4 -> 3 -> null -> Option AQuick Check:
Alternate front and back nodes = 1 -> 5 -> 2 -> 4 -> 3 -> null [OK]
- Reversing the entire list instead
- Keeping original order unchanged
- Mixing node order incorrectly
func reorderList(head *ListNode) {
if head == nil || head.Next == nil { return }
slow, fast := head, head
for fast != nil && fast.Next != nil {
slow = slow.Next
fast = fast.Next.Next
}
second := slow.Next
slow.Next = nil
var prev *ListNode
for second != nil {
next := second.Next
second.Next = prev
prev = second
second = next
}
first, second = head, prev
for second != nil {
tmp1 := first.Next
tmp2 := second.Next
first.Next = second
second.Next = tmp1
first = tmp1
second = tmp2
}
}
What is the bug in this code?Solution
Step 1: Analyze the reversal and merging steps
The code correctly finds the middle, reverses the second half, and then merges nodes alternately.Step 2: Identify the bug in linking halves
After merging, the last node of the reordered list may still point to old nodes if not handled carefully. The code misses ensuring the last node's Next is nil, causing potential cycle or dangling links.Final Answer:
The reversed second half is not properly linked back to the first half -> Option DQuick Check:
Linking halves correctly is key [OK]
- Not breaking the list at middle properly
- Forgetting to set slow.Next = nil
- Incorrect pointer updates in merge loop
Solution
Step 1: Apply reorder once
First reorder transforms 1->2->3 into 1->3->2.Step 2: Apply reorder again on the new list
Reordering 1->3->2 again returns the original order 1->2->3 because the reorder pattern is symmetric and reverses itself on second application.Final Answer:
1 -> 2 -> 3 -> null (original list) -> Option CQuick Check:
Reorder twice returns original list [OK]
- Assuming reorder twice keeps the first reorder result
- Not recognizing reorder symmetry
- Confusing reorder with reverse
Ready to prove it?
Pass the test and this pattern moves unknown
