Find Middle Element of Linked List in DSA C++ - Time & Space Complexity
We want to understand how long it takes to find the middle element in a linked list as the list grows.
How does the time needed change when the list gets bigger?
Analyze the time complexity of the following code snippet.
struct Node {
int data;
Node* next;
};
Node* findMiddle(Node* head) {
Node* slow = head;
Node* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
This code finds the middle node by moving one pointer twice as fast as the other.
Identify the loops, recursion, array traversals that repeat.
- Primary operation: The while loop that moves the fast pointer two steps and slow pointer one step.
- How many times: The loop runs about n/2 times, where n is the number of nodes in the list.
As the list size grows, the number of loop steps grows roughly half as fast.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 5 |
| 100 | 50 |
| 1000 | 500 |
Pattern observation: The operations grow linearly with input size, just half as many steps.
Time Complexity: O(n)
This means the time to find the middle grows directly with the size of the list.
[X] Wrong: "The loop runs n times because it looks like it moves one step at a time."
[OK] Correct: The fast pointer moves two steps each loop, so the loop count is about half n, not n.
Understanding this pattern helps you explain how to efficiently find middle elements without extra space, a common skill interviewers appreciate.
"What if we used only one pointer moving one step at a time and counted nodes first? How would the time complexity change?"
Practice
Solution
Step 1: Understand the two-pointer technique
The fast pointer moves two nodes at a time, and the slow pointer moves one node at a time.Step 2: Identify the middle when fast pointer reaches the end
When the fast pointer reaches the end (null), the slow pointer will be at the middle node.Final Answer:
Use two pointers, one moving twice as fast as the other; when the fast pointer reaches the end, the slow pointer is at the middle. -> Option AQuick Check:
Two-pointer approach = Fast and slow pointers [OK]
- Trying to reverse the list unnecessarily
- Counting nodes twice instead of one pass
- Using extra space like stack without need
head?Solution
Step 1: Initialize both pointers at the head
Both slow and fast pointers should start at the head to traverse the list correctly.Step 2: Avoid null initialization for slow or fast
Initializing slow or fast to nullptr will cause errors or skip nodes.Final Answer:
ListNode* slow = head; ListNode* fast = head; -> Option DQuick Check:
Both pointers start at head [OK]
- Initializing pointers to nullptr causing runtime errors
- Starting slow pointer at head->next skipping first node
- Starting fast pointer at nullptr causing immediate stop
struct Node {
int data;
Node* next;
};
Node* findMiddle(Node* head) {
Node* slow = head;
Node* fast = head;
while (fast != nullptr && fast->next != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}
int main() {
Node n1 = {1, nullptr};
Node n2 = {2, nullptr};
Node n3 = {3, nullptr};
Node n4 = {4, nullptr};
Node n5 = {5, nullptr};
n1.next = &n2;
n2.next = &n3;
n3.next = &n4;
n4.next = &n5;
Node* mid = findMiddle(&n1);
std::cout << mid->data << std::endl;
return 0;
}Solution
Step 1: Trace slow and fast pointers through the list
Initially, slow=1, fast=1; after first loop, slow=2, fast=3; second loop, slow=3, fast=5; next loop fast->next is nullptr, stop.Step 2: Identify slow pointer position at loop end
Slow pointer is at node with data 3, which is the middle element.Final Answer:
3 -> Option AQuick Check:
Middle element = 3 [OK]
- Assuming middle is 2 or 4 instead of 3
- Not checking fast->next before moving fast
- Confusing zero-based indexing with node values
Node* findMiddle(Node* head) {
Node* slow = head;
Node* fast = head;
while (fast != nullptr) {
slow = slow->next;
fast = fast->next->next;
}
return slow;
}Solution
Step 1: Analyze the while loop condition
The loop only checks if fast != nullptr, but fast->next might be nullptr causing a crash when accessing fast->next->next.Step 2: Correct the condition to check fast->next as well
Change the loop condition to while (fast != nullptr && fast->next != nullptr) to safely move fast pointer two steps.Final Answer:
The while condition should check both fast and fast->next to avoid null pointer dereference. -> Option BQuick Check:
Check fast and fast->next before moving fast [OK]
- Not checking fast->next causing runtime errors
- Moving slow pointer two steps incorrectly
- Returning wrong pointer at the end
Solution
Step 1: Understand default behavior for even length lists
Normally, with both pointers starting at head, slow ends at the second middle node for even length lists.Step 2: Modify fast pointer start to head->next
Starting fast at head->next causes slow to stop at the first middle node when fast reaches the end.Final Answer:
Initialize fast pointer to head->next instead of head. -> Option CQuick Check:
Fast starts at head->next for first middle [OK]
- Changing slow pointer start instead of fast
- Moving fast pointer one step breaks logic
- Using extra space unnecessarily
Ready to prove it?
Pass the test and this pattern moves unknown
