Lesson 43 of 164
Reverse a Linked List From Position m to n
Given the head of a singly linked list and two positions m <= n (counting from 1), reverse the nodes from position m to position n and return the head.
LeetCode: 92. Reverse Linked List II
Example
Input: 15 -> 20 -> 25 -> 30 -> 35, m = 2, n = 4
Output: 15 -> 30 -> 25 -> 20 -> 35
Input: 20 -> 40 -> 60 -> 70, m = 2, n = 3
Output: 20 -> 60 -> 40 -> 70Brute force: reverse the values
Copy the values into an int[], reverse the range m - 1 to n - 1 in place with two indexes that move toward each other, and build a new list.
A list node here is an object with a mutable next field, and null marks the end of the list.
import java.util.ArrayList;
import java.util.List;
public class Main {
static class ListNode {
int val;
ListNode next;
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
static ListNode reverseBetween(ListNode head, int m, int n) {
List<Integer> values = new ArrayList<>();
for (ListNode node = head; node != null; node = node.next) values.add(node.val);
for (int i = m - 1, j = n - 1; i < j; i++, j--) {
int tmp = values.get(i);
values.set(i, values.get(j));
values.set(j, tmp);
}
ListNode result = null;
for (int i = values.size() - 1; i >= 0; i--) {
result = new ListNode(values.get(i), result);
}
return result;
}
static ListNode fromArray(int... values) {
ListNode head = null;
for (int i = values.length - 1; i >= 0; i--) {
head = new ListNode(values[i], head);
}
return head;
}
static String show(ListNode list) {
StringBuilder sb = new StringBuilder("[");
for (ListNode n = list; n != null; n = n.next) {
if (n != list) sb.append(", ");
sb.append(n.val);
}
return sb.append("]").toString();
}
public static void main(String[] args) {
System.out.println(show(reverseBetween(fromArray(15, 20, 25, 30, 35), 2, 4)));
}
}[15, 30, 25, 20, 35]Time: O(len). Space: O(len), and it rebuilds nodes instead of moving them.
Optimal: relink the segment in one pass
- Put a dummy node in front of the head and walk
beforeforwardm - 1steps.beforeis now the node right before positionm. The dummy makesm == 1work with no special case. - Let
startbebefore.next. It is the first node of the segment and ends up as the last one. - Repeat
n - mtimes: take the node afterstart(call itmoved), cut it out, and insert it right afterbefore.
15 -> [20 -> 25 -> 30] -> 35
reverse segment
15 -> [30 -> 25 -> 20] -> 35Walkthrough with 15 -> 20 -> 25 -> 30 -> 35, m = 2, n = 4. Here before is 15 and start is 20.
| step | moved |
list after |
|---|---|---|
| 1 | 25 | 15 -> 25 -> 20 -> 30 -> 35 |
| 2 | 30 | 15 -> 30 -> 25 -> 20 -> 35 |
public class Main {
static class ListNode {
int val;
ListNode next;
ListNode(int val, ListNode next) {
this.val = val;
this.next = next;
}
}
static ListNode reverseBetween(ListNode head, int m, int n) {
ListNode dummy = new ListNode(0, head);
ListNode before = dummy;
for (int i = 1; i < m; i++) before = before.next;
ListNode start = before.next;
for (int i = 0; i < n - m; i++) {
ListNode moved = start.next;
start.next = moved.next; // cut `moved` out of the segment
moved.next = before.next; // put it at the front of the segment
before.next = moved;
}
return dummy.next;
}
static ListNode fromArray(int... values) {
ListNode head = null;
for (int i = values.length - 1; i >= 0; i--) {
head = new ListNode(values[i], head);
}
return head;
}
static String show(ListNode list) {
StringBuilder sb = new StringBuilder("[");
for (ListNode n = list; n != null; n = n.next) {
if (n != list) sb.append(", ");
sb.append(n.val);
}
return sb.append("]").toString();
}
public static void main(String[] args) {
System.out.println(show(reverseBetween(fromArray(15, 20, 25, 30, 35), 2, 4)));
System.out.println(show(reverseBetween(fromArray(20, 40, 60, 70), 2, 3)));
System.out.println(show(reverseBetween(fromArray(1, 2, 3), 1, 3)));
System.out.println(show(reverseBetween(fromArray(1, 2, 3), 2, 2)));
}
}[15, 30, 25, 20, 35]
[20, 60, 40, 70]
[3, 2, 1]
[1, 2, 3]Time: O(n): m - 1 steps to reach before, then n - m relinks. Space: O(1).
start never moves. Each round pulls the node after start to the front of the segment, so start drifts to the end of the segment and its next always points at the first node after the segment. No separate step is needed to attach the rest of the list.
Edge cases
m == n: the loop runs zero times; the list is unchanged.m == 1:beforeis the dummy node, so the head itself is replaced anddummy.nextis the new head.nequal to the length:moved.nextbecomesnullat the last step, which correctly ends the list.
