LeetCode 206: Reverse Linked List
-
- [1. Problem Link 🔗](#1. Problem Link 🔗)
- [2. Solution Overview 🧭](#2. Solution Overview 🧭)
- [3. Solution 1: Iterative Approach (Recommended)](#3. Solution 1: Iterative Approach (Recommended))
-
- [3.1. Algorithm](#3.1. Algorithm)
- [3.2. Important Points](#3.2. Important Points)
- [3.3. Java Implementation](#3.3. Java Implementation)
- [3.4. Time & Space Complexity](#3.4. Time & Space Complexity)
- [4. Solution 2: Recursive Approach](#4. Solution 2: Recursive Approach)
-
- [4.1. Algorithm](#4.1. Algorithm)
- [4.2. Important Points](#4.2. Important Points)
- [4.3. Java Implementation](#4.3. Java Implementation)
- [4.4. Time & Space Complexity](#4.4. Time & Space Complexity)
- [5. Solution 3: Recursive with Helper Function](#5. Solution 3: Recursive with Helper Function)
-
- [5.1. Algorithm](#5.1. Algorithm)
- [5.2. Important Points](#5.2. Important Points)
- [5.3. Java Implementation](#5.3. Java Implementation)
- [5.4. Time & Space Complexity](#5.4. Time & Space Complexity)
- [6. Solution 4: Iterative with Dummy Node](#6. Solution 4: Iterative with Dummy Node)
-
- [6.1. Algorithm](#6.1. Algorithm)
- [6.2. Important Points](#6.2. Important Points)
- [6.3. Java Implementation](#6.3. Java Implementation)
- [6.4. Time & Space Complexity](#6.4. Time & Space Complexity)
- [7. Solution 5: Tail Recursive Approach](#7. Solution 5: Tail Recursive Approach)
-
- [7.1. Algorithm](#7.1. Algorithm)
- [7.2. Important Points](#7.2. Important Points)
- [7.3. Java Implementation](#7.3. Java Implementation)
- [7.4. Time & Space Complexity](#7.4. Time & Space Complexity)
- [8. Solution Comparison 📊](#8. Solution Comparison 📊)
- [9. Summary 📝](#9. Summary 📝)
1. Problem Link 🔗
LeetCode 206: Reverse Linked List
2. Solution Overview 🧭
Reverse a singly linked list. This is a fundamental linked list operation that appears frequently in interviews and real-world applications.
Example:
Input: 1 → 2 → 3 → 4 → 5 → NULL
Output: 5 → 4 → 3 → 2 → 1 → NULL
Constraints:
- The number of nodes in the list is the range
[0, 5000] -5000 <= Node.val <= 5000
Common approaches include:
- Iterative Approach: Use three pointers to reverse links one by one
- Recursive Approach: Recursively reverse the rest of the list and adjust pointers
- Stack-based Approach: Use stack to reverse order (less efficient)
3. Solution 1: Iterative Approach (Recommended)
3.1. Algorithm
- Use three pointers:
prev,current,next - Traverse the list, reversing the
nextpointer of each node - Move pointers forward until the entire list is reversed
3.2. Important Points
- Most efficient and intuitive
- O(1) space complexity
- Easy to understand and implement
3.3. Java Implementation
java
/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode current = head;
while (current != null) {
ListNode nextTemp = current.next; // Store next node
current.next = prev; // Reverse the link
prev = current; // Move prev forward
current = nextTemp; // Move current forward
}
return prev; // New head of reversed list
}
}
3.4. Time & Space Complexity
- Time Complexity: O(n)
- Space Complexity: O(1)
4. Solution 2: Recursive Approach
4.1. Algorithm
- Recursively reverse the rest of the list (head.next)
- Adjust pointers so that the current node becomes the last node
- The base case handles the end of the list
4.2. Important Points
- Elegant but uses O(n) stack space
- Good for understanding recursion
- May cause stack overflow for very long lists
4.3. Java Implementation
java
class Solution {
public ListNode reverseList(ListNode head) {
// Base case: empty list or single node
if (head == null || head.next == null) {
return head;
}
// Recursively reverse the rest of the list
ListNode newHead = reverseList(head.next);
// Adjust pointers: make current node the next of the last node
head.next.next = head;
head.next = null;
return newHead;
}
}
4.4. Time & Space Complexity
- Time Complexity: O(n)
- Space Complexity: O(n) - recursion stack
5. Solution 3: Recursive with Helper Function
5.1. Algorithm
- Use a helper function to carry the previous node through recursion
- Similar to iterative approach but implemented recursively
- More intuitive for some developers
5.2. Important Points
- Combines recursion with iterative logic
- Easier to understand for some
- Still uses O(n) stack space
5.3. Java Implementation
java
class Solution {
public ListNode reverseList(ListNode head) {
return reverseHelper(head, null);
}
private ListNode reverseHelper(ListNode current, ListNode prev) {
// Base case: reached end of list
if (current == null) {
return prev;
}
// Store next node before reversing
ListNode nextTemp = current.next;
// Reverse the current node
current.next = prev;
// Recursively process the next node
return reverseHelper(nextTemp, current);
}
}
5.4. Time & Space Complexity
- Time Complexity: O(n)
- Space Complexity: O(n) - recursion stack
6. Solution 4: Iterative with Dummy Node
6.1. Algorithm
- Use a dummy node to simplify edge cases
- Build the reversed list by inserting nodes at the beginning
- More explicit but slightly more memory usage
6.2. Important Points
- Handles edge cases gracefully
- Clear separation of concerns
- Good for learning purposes
6.3. Java Implementation
java
class Solution {
public ListNode reverseList(ListNode head) {
if (head == null) return null;
ListNode dummy = new ListNode(0);
ListNode current = head;
while (current != null) {
ListNode nextTemp = current.next;
// Insert current node at the beginning of reversed list
current.next = dummy.next;
dummy.next = current;
current = nextTemp;
}
return dummy.next;
}
}
6.4. Time & Space Complexity
- Time Complexity: O(n)
- Space Complexity: O(1)
7. Solution 5: Tail Recursive Approach
7.1. Algorithm
- Optimized recursive approach that could benefit from tail call optimization
- Some compilers can optimize this to use O(1) stack space
- Clean functional programming style
7.2. Important Points
- Potentially more efficient recursion
- Clean mathematical approach
- Java doesn't guarantee tail call optimization
7.3. Java Implementation
java
class Solution {
public ListNode reverseList(ListNode head) {
return tailReverse(head, null);
}
private ListNode tailReverse(ListNode head, ListNode newHead) {
if (head == null) {
return newHead;
}
ListNode next = head.next;
head.next = newHead;
return tailReverse(next, head);
}
}
7.4. Time & Space Complexity
- Time Complexity: O(n)
- Space Complexity: O(n) - though tail recursive, Java doesn't optimize
8. Solution Comparison 📊
| Solution | Time Complexity | Space Complexity | Advantages | Disadvantages |
|---|---|---|---|---|
| Iterative | O(n) | O(1) | Most efficient, intuitive | None significant |
| Recursive | O(n) | O(n) | Elegant, educational | Stack overflow risk |
| Recursive Helper | O(n) | O(n) | Combines recursion with iteration | Still uses stack space |
| Iterative with Dummy | O(n) | O(1) | Handles edges well | Slight memory overhead |
| Tail Recursive | O(n) | O(n) | Clean functional style | No optimization in Java |
9. Summary 📝
- Key Insight: Reversing a linked list involves changing the direction of pointers while maintaining access to remaining nodes
- Recommended Approach: Solution 1 (Iterative) for production code due to O(1) space
- Recursive Insight: The recursive approach beautifully demonstrates divide-and-conquer by reversing the rest first
- Pattern Recognition: This is a fundamental pattern for linked list manipulation
Recursive Thinking Process:
- Base case: empty list or single node is already reversed
- Recursively reverse everything after the current node
- Make the current node point to the new last node
- Make the last node point back to current node
- Break the original link to avoid cycles
For most practical purposes, the iterative approach is preferred, but understanding recursion is crucial for advanced algorithm problems.