Reverse a Singly Linked List Recursive in DSA Python - Time & Space Complexity
When reversing a singly linked list using recursion, we want to know how the time needed grows as the list gets longer.
We ask: How many steps does it take to reverse a list of size n?
Analyze the time complexity of the following code snippet.
class Node:
def __init__(self, val):
self.val = val
self.next = None
def reverse_recursive(head):
if head is None or head.next is None:
return head
new_head = reverse_recursive(head.next)
head.next.next = head
head.next = None
return new_head
This code reverses a singly linked list by calling itself on the next node until it reaches the end, then rewires the links backward.
- Primary operation: Recursive call on each node of the list.
- How many times: Exactly once per node, so n times for a list of size n.
Each node causes one recursive call, so the total steps grow directly with the number of nodes.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | About 10 recursive calls and rewiring steps |
| 100 | About 100 recursive calls and rewiring steps |
| 1000 | About 1000 recursive calls and rewiring steps |
Pattern observation: The work grows linearly as the list size increases.
Time Complexity: O(n)
This means the time to reverse the list grows in direct proportion to the number of nodes.
[X] Wrong: "Recursion makes this slower than a loop, so it must be more than O(n)."
[OK] Correct: Each node is still visited once, so recursion does not add extra visits; it just changes how the calls are made.
Understanding recursive reversal shows you can think about problems in different ways and handle linked lists confidently, a key skill in many coding challenges.
"What if we changed the recursion to an iterative loop? How would the time complexity change?"
Practice
Solution
Step 1: Understand recursion on linked list
The function calls itself on the next node until it reaches the end (base case).Step 2: Reverse pointers on return
After reaching the end, it reverses the next pointer of the current node to point backward.Final Answer:
It reverses the rest of the list and then adjusts the current node's next pointer. -> Option CQuick Check:
Recursive reversal = reverse rest + fix pointers [OK]
- Trying to swap node values instead of pointers
- Using loops instead of recursion
- Not handling the base case properly
Solution
Step 1: Identify base case meaning
The base case stops recursion when the list is empty or has one node.Step 2: Check correct condition
When head is None (empty) or head.next is None (single node), return head as reversed list.Final Answer:
if head is None or head.next is None: return head -> Option DQuick Check:
Base case = empty or single node [OK]
- Returning None incorrectly for single node
- Missing the empty list check
- Returning head.next instead of head
Solution
Step 1: Trace recursive calls
Function calls itself on 2 -> 3 -> None, then on 3 -> None (base case).Step 2: Reverse pointers on return
On return, 3 points to 2, 2 points to 1, and 1 points to None.Final Answer:
3 -> 2 -> 1 -> None -> Option BQuick Check:
Reversed list = 3 -> 2 -> 1 [OK]
- Not updating the last node's next pointer
- Returning original head instead of new head
- Confusing node values with pointers
def reverse(head):
if head is None:
return None
new_head = reverse(head.next)
head.next.next = head
head.next = None
return new_headSolution
Step 1: Analyze base case
Base case only checks if head is None, but not if head.next is None (single node).Step 2: Identify error cause
When head.next is None, head.next.next causes AttributeError because head.next is None.Final Answer:
Base case misses single node check causing AttributeError -> Option AQuick Check:
Missing single node base case = error [OK]
- Ignoring single node base case
- Changing pointers before recursion
- Returning None instead of new head
Solution
Step 1: Understand tail tracking need
To get tail efficiently, return it along with new head during recursion.Step 2: Modify function to return tuple
Return (new_head, tail) from recursive calls and update tail as current node.Step 3: Avoid extra traversal
This avoids traversing reversed list again, improving efficiency.Final Answer:
Return a tuple (new_head, tail) and update tail during recursion -> Option AQuick Check:
Return (head, tail) tuple for efficiency [OK]
- Using global variables causing side effects
- Traversing list again after reversal
- Ignoring tail node requirement
Ready to prove it?
Pass the test and this pattern moves unknown
