🧠
Recursive Approach to Reverse Sublist
💡 This approach uses recursion to reverse the sublist, which helps understand the problem from a different perspective and can be elegant but less intuitive for beginners.
Intuition
Recursively move to the left position, then reverse the next (right - left + 1) nodes, reconnecting as recursion unwinds.
Algorithm
- Define a helper function to reverse the first n nodes of a list.
- Recursively move head forward until left == 1.
- Use the helper to reverse the first (right - left + 1) nodes.
- Reconnect reversed sublist with the rest of the list.
💡 Recursion abstracts the pointer manipulation but requires careful base cases and understanding of recursion flow.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
successor = None
def reverseN(head, n):
global successor
if n == 1:
successor = head.next
return head
last = reverseN(head.next, n - 1)
head.next.next = head
head.next = successor
return last
def reverseBetween(head, left, right):
if left == 1:
return reverseN(head, right)
head.next = reverseBetween(head.next, left - 1, right - 1)
return head
# Driver code
if __name__ == '__main__':
nodes = [ListNode(i) for i in range(1, 6)]
for i in range(4):
nodes[i].next = nodes[i+1]
new_head = reverseBetween(nodes[0], 2, 4)
curr = new_head
while curr:
print(curr.val, end=' ')
curr = curr.next
print()
Line Notes
if n == 1:Base case: stop recursion after reversing n nodes
successor = head.nextStore the node after reversed sublist to reconnect later
head.next.next = headReverse pointer direction between two nodes
head.next = successorReconnect reversed sublist to the rest of the list
class ListNode {
int val;
ListNode next;
ListNode(int val) { this.val = val; }
}
public class Solution {
private ListNode successor = null;
public ListNode reverseN(ListNode head, int n) {
if (n == 1) {
successor = head.next;
return head;
}
ListNode last = reverseN(head.next, n - 1);
head.next.next = head;
head.next = successor;
return last;
}
public ListNode reverseBetween(ListNode head, int left, int right) {
if (left == 1) {
return reverseN(head, right);
}
head.next = reverseBetween(head.next, left - 1, right - 1);
return head;
}
public static void main(String[] args) {
Solution sol = new Solution();
ListNode[] nodes = new ListNode[5];
for (int i = 0; i < 5; i++) nodes[i] = new ListNode(i + 1);
for (int i = 0; i < 4; i++) nodes[i].next = nodes[i + 1];
ListNode newHead = sol.reverseBetween(nodes[0], 2, 4);
ListNode curr = newHead;
while (curr != null) {
System.out.print(curr.val + " ");
curr = curr.next;
}
System.out.println();
}
}
Line Notes
if (n == 1)Base case to stop recursion after reversing n nodes
successor = head.next;Keep track of node after reversed sublist for reconnection
head.next.next = head;Reverse pointer direction between two nodes
head.next = successor;Reconnect reversed sublist to remainder of list
#include <iostream>
using namespace std;
struct ListNode {
int val;
ListNode* next;
ListNode(int x) : val(x), next(nullptr) {}
};
ListNode* successor = nullptr;
ListNode* reverseN(ListNode* head, int n) {
if (n == 1) {
successor = head->next;
return head;
}
ListNode* last = reverseN(head->next, n - 1);
head->next->next = head;
head->next = successor;
return last;
}
ListNode* reverseBetween(ListNode* head, int left, int right) {
if (left == 1) {
return reverseN(head, right);
}
head->next = reverseBetween(head->next, left - 1, right - 1);
return head;
}
int main() {
ListNode* nodes[5];
for (int i = 0; i < 5; i++) nodes[i] = new ListNode(i + 1);
for (int i = 0; i < 4; i++) nodes[i]->next = nodes[i + 1];
ListNode* newHead = reverseBetween(nodes[0], 2, 4);
ListNode* curr = newHead;
while (curr) {
cout << curr->val << " ";
curr = curr->next;
}
cout << endl;
return 0;
}
Line Notes
if (n == 1)Base case to stop recursion after reversing n nodes
successor = head->next;Store node after reversed sublist for reconnection
head->next->next = head;Reverse pointer direction between two nodes
head->next = successor;Reconnect reversed sublist to remainder of list
class ListNode {
constructor(val = 0, next = null) {
this.val = val;
this.next = next;
}
}
let successor = null;
function reverseN(head, n) {
if (n === 1) {
successor = head.next;
return head;
}
let last = reverseN(head.next, n - 1);
head.next.next = head;
head.next = successor;
return last;
}
function reverseBetween(head, left, right) {
if (left === 1) {
return reverseN(head, right);
}
head.next = reverseBetween(head.next, left - 1, right - 1);
return head;
}
// Test
const nodes = [1,2,3,4,5].map(v => new ListNode(v));
for (let i = 0; i < 4; i++) nodes[i].next = nodes[i+1];
const newHead = reverseBetween(nodes[0], 2, 4);
let curr = newHead;
let output = [];
while (curr) {
output.push(curr.val);
curr = curr.next;
}
console.log(output.join(' '));
Line Notes
if (n === 1)Base case to stop recursion after reversing n nodes
successor = head.next;Store node after reversed sublist for reconnection
head.next.next = head;Reverse pointer direction between two nodes
head.next = successor;Reconnect reversed sublist to remainder of list
Recursion depth can be up to n, so time is linear but space is linear due to call stack.
💡 For large n, recursion may cause stack overflow, so iterative is preferred.
Interview Verdict: Accepted but less practical
Elegant but recursion depth and complexity make it less ideal for interviews compared to iterative.