Given the head of a singly linked list and two integers left
and right
(with 1-based indexing), reverse the nodes of the list from position left
to position right
, and return the modified list's head. The reversal should be done in-place and only the nodes between left
and right
(inclusive) are affected. All other nodes must remain in their original order and should not be recreated or reused. Only one valid solution is required, and you may not reuse or create new nodes for the reversed portion.
head
(the head of a singly linked list), left
(integer), right
(integer)left
≤ right
≤ length of list
The problem asks us to reverse a segment of a singly linked list, specifically from position left
to right
. At first glance, one might consider extracting the sublist, reversing it, and then reconnecting it. However, since the reversal must be done in-place and without creating new nodes, we need to manipulate the pointers directly.
The brute-force approach would be to traverse the list, copy the values of the segment into an array, reverse the array, and write them back. However, this would violate the in-place constraint and waste space.
Instead, by carefully keeping track of the nodes before, within, and after the segment to reverse, we can perform the reversal efficiently by re-pointing the next
pointers. This requires careful pointer manipulation but is optimal in both time and space.
We will reverse the sublist in-place by manipulating pointers. Here’s a step-by-step plan:
left = 1
, we introduce a dummy node before the head. This simplifies pointer management at the head.
left
: Let’s call this node prev
. This node will connect to the reversed segment's head after reversal.
left
, we iteratively reverse the next
pointers for right - left + 1
nodes.
prev.next
to the new head of the reversed segment, and the tail of the reversed segment to the node after right
.
dummy.next
.
This approach ensures all pointer changes are performed in-place, and only the specified segment is reversed.
Let’s walk through an example:
Input: head = [1, 2, 3, 4, 5]
, left = 2
, right = 4
dummy → 1 → 2 → 3 → 4 → 5
prev
to node 1 (the node before position 2).
curr = 2
, detach 3
and insert after prev
→ dummy → 1 → 3 → 2 → 4 → 5
curr = 2
, detach 4
and insert after prev
→ dummy → 1 → 4 → 3 → 2 → 5
1 → 4 → 3 → 2 → 5
dummy.next
as the new head.
The sublist from position 2 to 4 has been reversed, and all other nodes remain in order.
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
class Solution:
def reverseBetween(self, head: ListNode, left: int, right: int) -> ListNode:
if not head or left == right:
return head
dummy = ListNode(0)
dummy.next = head
prev = dummy
# Move prev to the node before 'left'
for _ in range(left - 1):
prev = prev.next
# Start reversing
curr = prev.next
for _ in range(right - left):
temp = curr.next
curr.next = temp.next
temp.next = prev.next
prev.next = temp
return dummy.next
/**
* Definition for singly-linked list.
* struct ListNode {
* int val;
* ListNode *next;
* ListNode() : val(0), next(nullptr) {}
* ListNode(int x) : val(x), next(nullptr) {}
* ListNode(int x, ListNode *next) : val(x), next(next) {}
* };
*/
class Solution {
public:
ListNode* reverseBetween(ListNode* head, int left, int right) {
if (!head || left == right) return head;
ListNode dummy(0);
dummy.next = head;
ListNode* prev = &dummy;
// Move prev to the node before 'left'
for (int i = 0; i < left - 1; ++i) {
prev = prev->next;
}
ListNode* curr = prev->next;
for (int i = 0; i < right - left; ++i) {
ListNode* temp = curr->next;
curr->next = temp->next;
temp->next = prev->next;
prev->next = temp;
}
return dummy.next;
}
};
/**
* 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 reverseBetween(ListNode head, int left, int right) {
if (head == null || left == right) return head;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prev = dummy;
// Move prev to the node before 'left'
for (int i = 0; i < left - 1; ++i) {
prev = prev.next;
}
ListNode curr = prev.next;
for (int i = 0; i < right - left; ++i) {
ListNode temp = curr.next;
curr.next = temp.next;
temp.next = prev.next;
prev.next = temp;
}
return dummy.next;
}
}
/**
* Definition for singly-linked list.
* function ListNode(val, next) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
*/
/**
* @param {ListNode} head
* @param {number} left
* @param {number} right
* @return {ListNode}
*/
var reverseBetween = function(head, left, right) {
if (!head || left === right) return head;
let dummy = new ListNode(0, head);
let prev = dummy;
// Move prev to the node before 'left'
for (let i = 0; i < left - 1; ++i) {
prev = prev.next;
}
let curr = prev.next;
for (let i = 0; i < right - left; ++i) {
let temp = curr.next;
curr.next = temp.next;
temp.next = prev.next;
prev.next = temp;
}
return dummy.next;
};
left
, and once to reverse up to right
).The optimized solution is both time and space efficient, making it suitable for large lists.
To reverse a sublist of a singly linked list between two given positions, we use a dummy node to simplify pointer manipulation, locate the node before the reversal segment, and perform in-place pointer reversal for the specified range. This method is efficient, elegant, and adheres to the problem's constraints of in-place reversal and no node reuse. The key insight is to manipulate pointers directly, avoiding unnecessary space usage and achieving O(N) time and O(1) space complexity.