Reverse Linked List in C#
1. The Problem: Reverse Linked List
Given the head of a singly linked list, reverse the list, and return the reversed list.
Example 1:
- Input:
head = [1,2,3,4,5] - Output:
[5,4,3,2,1]
Example 2:
- Input:
head = [1,2] - Output:
[2,1]
Example 3:
- Input:
head = [] - Output:
[]
2. The Intuition: Iterative vs Recursive
Reversing a linked list can be done in two primary ways:
- Iterative Approach: We use three pointers (
prev,curr,next) to flip thenextpointer of each node as we traverse the list. This is memory-efficient as it only uses constant extra space. - Recursive Approach: We break the problem down by reversing the “rest of the list” first, then making the original second node point back to the first node. While elegant, it uses more memory due to the recursion stack.
Iterative Logic:
- Initialize Pointers: We need three pointers:
prev(initiallynull),curr(initiallyhead), andnext(to temporary store the next node). - Traverse and Flip: While
curris notnull:- Store the
nextnode:next = curr.next. - Reverse the link:
curr.next = prev. - Move
prevforward:prev = curr. - Move
currforward:curr = next.
- Store the
- Return New Head: Once
currbecomesnull,prevwill be pointing to the new head.
Recursive Logic (NeetCode):
- Base Case: If the list is empty or has only one node, return the
head. - Recurse: Recursively call
ReverseListon the next node (head.next). This returns the new head of the reversed portion. - Link Back: Set the
nextof the original next node to the currenthead(head.next.next = head). - Clean Up: Set
head.nexttonullto avoid cycles.
3. Solution 1: Iterative Approach
This approach is efficient and easy to implement. It reverses the list in-place without needing extra space for a new list.
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int val=0, ListNode next=null) {
* this.val = val;
* this.next = next;
* }
* }
*/
public class Solution {
public ListNode ReverseList(ListNode head) {
ListNode prev = null;
var curr = head;
while (curr != null) {
var next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}
}
4. Solution 2: Recursive Approach (NeetCode)
This NeetCode.io approach uses recursion to reach the end of the list first, then reverses the pointers as the call stack unwinds.
/**
* Definition for singly-linked list.
* public class ListNode {
* public int val;
* public ListNode next;
* public ListNode(int val=0, ListNode next=null) {
* this.val = val;
* this.next = next;
* }
* }
*/
public class Solution {
public ListNode ReverseList(ListNode head) {
if (head == null) {
return null;
}
ListNode newHead = head;
if (head.next != null) {
newHead = ReverseList(head.next);
head.next.next = head;
}
head.next = null;
return newHead;
}
}
5. Complexity Analysis
| Approach | Time Complexity | Space Complexity | Why? |
|---|---|---|---|
| Iterative | O(N) | O(1) | Single pass, constant extra pointer variables. |
| Recursive | O(N) | O(N) | Single pass, but uses the call stack for each node. |
- Time Complexity: O(N) for both, where N is the number of nodes in the linked list.
- Space Complexity: Iterative is O(1), while recursive is O(N) due to the stack depth.
6. Summary
Reversing a linked list is a fundamental problem that tests your understanding of pointer manipulation. The iterative approach is generally preferred in production because it avoids potential stack overflow issues for very large lists. The recursive approach, however, is often considered more elegant and is a great way to practice recursive thinking.
Leave a comment