Pattern family: LinkedList Manipulation Notes & Templates: 01_inplace_reversal_notes.md Language: Java
- P3 β Reverse List in Pairs
- P4 β Reverse Every K-element Sub-list
- P7 β Reverse Alternate K Elements
- P10 β Sort List
- P11 β Remove Nth Node From End of List
- P12 β Add Two Numbers
- P13 β Copy List with Random Pointer
- P14 β Merge Two Sorted Lists
LeetCode #206 | Difficulty: Easy | Variant: Full reversal
| Step | Loop over | Condition | Result |
|---|---|---|---|
| 1 | curr from head to null |
always | save next, flip, advance both |
| 2 | β | curr == null |
return prev as new head |
public ListNode reverseList(ListNode head) {
ListNode prev = null;
ListNode curr = head;
while (curr != null) {
ListNode next = curr.next; // Step 1: save
curr.next = prev; // Step 2: flip
prev = curr; // Step 3: advance prev
curr = next; // Step 4: advance curr
}
return prev; // new head of reversed list
}Input: 1 β 2 β 3 β 4 β 5 β null
Trace:
prev=null, curr=1 β next=2, 1.next=null, prev=1, curr=2
prev=1, curr=2 β next=3, 2.next=1, prev=2, curr=3
prev=2, curr=3 β next=4, 3.next=2, prev=3, curr=4
prev=3, curr=4 β next=5, 4.next=3, prev=4, curr=5
prev=4, curr=5 β next=null, 5.next=4, prev=5, curr=null
curr==null β stop
Output: 5 β 4 β 3 β 2 β 1 β null
LeetCode #92 | Difficulty: Medium | Variant: Partial reversal with skip and reconnect
| Step | Action | Note |
|---|---|---|
| 1 | Walk to node at position (p-1), save as beforeP |
needed for left reconnect |
| 2 | curr is now the start of reversal (position p) |
save as tailOfSegment |
| 3 | Reverse (q-p+1) nodes with 4-line loop | |
| 4 | beforeP.next = newHead |
connect left to reversed segment |
| 5 | tailOfSegment.next = curr |
connect reversed tail to right part |
public ListNode reverseBetween(ListNode head, int p, int q) {
if (head == null || p == q) return head;
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode beforeP = dummy;
// Step 1: walk to the node just before position p
for (int i = 1; i < p; i++)
beforeP = beforeP.next;
// Step 2: curr is now at position p (start of reversal)
ListNode tailOfSegment = beforeP.next; // after reversal this becomes the tail
ListNode curr = tailOfSegment;
// Step 3: reverse (q - p + 1) nodes
ListNode prev = null;
for (int i = 0; i <= q - p; i++) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
// Step 4: reconnect
beforeP.next = prev; // left part β new head of reversed segment
tailOfSegment.next = curr; // tail of reversed segment β right part
return dummy.next;
}Input: 1 β 2 β 3 β 4 β 5 β null, p=2, q=4
Walk to beforeP (position 1): beforeP = node(1)
tailOfSegment = node(2)
Reverse 3 nodes [2,3,4]: prev = node(4)βnode(3)βnode(2)βnull, curr = node(5)
Reconnect: node(1).next = node(4), node(2).next = node(5)
Output: 1 β 4 β 3 β 2 β 5 β null
LeetCode #24 | Difficulty: Medium | Variant: K=2 group reversal
| Step | Action | Note |
|---|---|---|
| 1 | Use dummy node, prevGroupTail = dummy |
anchor for reconnection |
| 2 | While 2 nodes exist: save first and second |
the pair to reverse |
| 3 | Reverse the pair: first.next=second.next, second.next=first |
simple swap for k=2 |
| 4 | prevGroupTail.next = second, prevGroupTail = first |
reconnect and advance |
public ListNode swapPairs(ListNode head) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prevGroupTail = dummy;
while (prevGroupTail.next != null && prevGroupTail.next.next != null) {
ListNode first = prevGroupTail.next; // 1st node of pair
ListNode second = prevGroupTail.next.next; // 2nd node of pair
// Reverse the pair
first.next = second.next; // detach first from second
second.next = first; // second points to first
prevGroupTail.next = second; // connect left part to second
prevGroupTail = first; // first is now the tail of this pair
}
return dummy.next;
}Input: 1 β 2 β 3 β 4 β null
Iteration 1: pair=(1,2) β swap β 2 β 1, prevGroupTail=node(1)
Iteration 2: pair=(3,4) β swap β 4 β 3, prevGroupTail=node(3)
No more pairs.
Output: 2 β 1 β 4 β 3 β null
LeetCode #25 | Difficulty: Hard | Variant: K-group reversal
| Step | Action | Note |
|---|---|---|
| 1 | Check if k nodes exist ahead | if fewer than k remain, stop |
| 2 | Save segmentTail = curr (will be tail after reversal) |
for reconnection |
| 3 | Reverse k nodes | use reverseSegment(curr, k) |
| 4 | prevGroupTail.next = newHead |
connect left to this group |
| 5 | segmentTail.next = curr |
connect this group's tail to next |
| 6 | Advance prevGroupTail = segmentTail, repeat |
public ListNode reverseKGroup(ListNode head, int k) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prevGroupTail = dummy;
while (true) {
// Check if k nodes exist from current position
ListNode check = prevGroupTail;
for (int i = 0; i < k; i++) {
check = check.next;
if (check == null) return dummy.next; // fewer than k nodes left
}
ListNode segmentTail = prevGroupTail.next; // will become tail after reverse
ListNode curr = prevGroupTail.next; // start of this group
// Reverse k nodes
ListNode prev = null;
for (int i = 0; i < k; i++) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
// Reconnect
prevGroupTail.next = prev; // left part β new head of group
segmentTail.next = curr; // group tail β start of next group
prevGroupTail = segmentTail; // advance boundary
}
}Input: 1 β 2 β 3 β 4 β 5 β null, k=3
Check: 3 nodes exist (1,2,3) β reverse β 3 β 2 β 1, curr=node(4)
Connect: dummyβ3, node(1)βnode(4)
Check from node(1): only 2 nodes (4,5) β fewer than k=3 β stop
Output: 3 β 2 β 1 β 4 β 5 β null
LeetCode #2074 | Difficulty: Hard | Variant: Conditional group reversal
| Step | Action | Note |
|---|---|---|
| 1 | Traverse group by group (group sizes: 1,2,3,4,...) | actual size may be less at end |
| 2 | Count actual nodes in this group | may be less than expected group size |
| 3 | If actual size is even β reverse this group | use standard reversal + reconnect |
| 4 | If actual size is odd β skip (leave as is) | just advance prevGroupTail |
| 5 | Repeat for next group |
public ListNode reverseEvenLengthGroups(ListNode head) {
ListNode prevGroupTail = head; // first group (size=1) always stays
int groupSize = 2; // start from group 2
while (prevGroupTail.next != null) {
// Count actual nodes in this group (may be less than groupSize)
ListNode node = prevGroupTail;
int actualSize = 0;
for (int i = 0; i < groupSize && node.next != null; i++) {
actualSize++;
node = node.next;
}
if (actualSize % 2 == 0) {
// Reverse this group
ListNode segmentTail = prevGroupTail.next;
ListNode curr = prevGroupTail.next;
ListNode prev = null;
for (int i = 0; i < actualSize; i++) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
prevGroupTail.next = prev;
segmentTail.next = curr;
prevGroupTail = segmentTail;
} else {
// Skip odd-size group β just advance prevGroupTail
for (int i = 0; i < actualSize; i++)
prevGroupTail = prevGroupTail.next;
}
groupSize++;
}
return head;
}Input: 5 β 2 β 6 β 3 β 9 β 1 β 7 β 3 β 8 β null
Groups: [5](size=1,oddβskip), [2,6](size=2,evenβreverseβ6,2), [3,9,1](size=3,oddβskip), [7,3,8](size=3,oddβskip)
Output: 5 β 6 β 2 β 3 β 9 β 1 β 7 β 3 β 8 β null
LeetCode #61 | Difficulty: Medium | Variant: Reconnect (no flip)
| Step | Action | Note |
|---|---|---|
| 1 | Find length of list and tail node | one pass |
| 2 | k = k % len β handle k > len |
if k==0, return head unchanged |
| 3 | Walk to node at position (len - k) β this becomes new tail |
|
| 4 | newHead = newTail.next |
the node after new tail is new head |
| 5 | tail.next = head then newTail.next = null |
form circle then break it |
public ListNode rotateRight(ListNode head, int k) {
if (head == null || head.next == null || k == 0) return head;
// Step 1: find length and tail
int len = 1;
ListNode tail = head;
while (tail.next != null) {
tail = tail.next;
len++;
}
// Step 2: reduce k
k = k % len;
if (k == 0) return head; // no rotation needed
// Step 3: find new tail at position (len - k)
ListNode newTail = head;
for (int i = 1; i < len - k; i++)
newTail = newTail.next;
// Step 4 & 5: reconnect
ListNode newHead = newTail.next;
newTail.next = null; // break the link
tail.next = head; // old tail β old head (connect the circle)
return newHead;
}Input: 1 β 2 β 3 β 4 β 5 β null, k=2
len=5, k=2%5=2
New tail at position (5-2)=3: node(3)
newHead = node(4)
tail(5).next = head(1) β circle
node(3).next = null β break
Output: 4 β 5 β 1 β 2 β 3 β null
Difficulty: Medium | Variant: Alternate reverse and skip
| Step | Action | Note |
|---|---|---|
| 1 | Reverse k nodes | standard reversal |
| 2 | Reconnect reversed group to list | prevTail.next = newHead, segTail.next = curr |
| 3 | Skip k nodes (leave in place) | advance curr by k |
| 4 | Repeat from step 1 |
public ListNode reverseAlternateKElements(ListNode head, int k) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode prevGroupTail = dummy;
ListNode curr = head;
while (curr != null) {
// Reverse k nodes
ListNode segTail = curr;
ListNode prev = null;
int count = k;
while (curr != null && count-- > 0) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
prevGroupTail.next = prev;
segTail.next = curr;
prevGroupTail = segTail;
// Skip k nodes
count = k;
while (curr != null && count-- > 0) {
prevGroupTail = curr;
curr = curr.next;
}
}
return dummy.next;
}Input: 1 β 2 β 3 β 4 β 5 β 6 β 7 β 8 β null, k=2
Reverse [1,2] β [2,1], skip [3,4], reverse [5,6] β [6,5], skip [7,8]
Output: 2 β 1 β 3 β 4 β 6 β 5 β 7 β 8 β null
LeetCode #234 | Difficulty: Easy | Variant: Reversal as a tool
| Step | Action | Note |
|---|---|---|
| 1 | Find middle using slow/fast pointers | slow = middle |
| 2 | Reverse second half from slow.next |
standard reversal |
| 3 | Compare first half and reversed second half | both must match |
| 4 | (Optional) Restore the list | reverse second half back |
public boolean isPalindrome(ListNode head) {
if (head == null || head.next == null) return true;
// Step 1: find middle
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// Step 2: reverse second half
ListNode secondHalfHead = reverse(slow.next);
// Step 3: compare
ListNode p1 = head, p2 = secondHalfHead;
while (p2 != null) {
if (p1.val != p2.val) return false;
p1 = p1.next;
p2 = p2.next;
}
return true;
}
private ListNode reverse(ListNode head) {
ListNode prev = null, curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}Input: 1 β 2 β 2 β 1 β null
Middle = node(2) (second one)
Reverse second half [2,1] β [1,2]
Compare: 1==1, 2==2 β true
Output: true
LeetCode #143 | Difficulty: Medium | Company: Amazon, Facebook | Category: Reversal as Tool
Reorder
L0 β L1 β ... β LntoL0 β Ln β L1 β Ln-1 β ...in-place.
3-step approach: (1) Find middle, (2) Reverse second half, (3) Merge alternately. Classic reversal-as-tool problem.
| Step | Action | Note |
|---|---|---|
| 1 | Find middle with slow/fast pointers | slow = mid |
| 2 | Reverse second half from slow.next |
standard reversal |
| 3 | slow.next = null β cut at middle |
separates two halves |
| 4 | Merge alternately: firstβlastβsecondβsecond-last... | interleave |
public void reorderList(ListNode head) {
if (head == null || head.next == null) return;
// Step 1: find middle
ListNode slow = head, fast = head;
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
// Step 2: reverse second half
ListNode second = reverse(slow.next);
slow.next = null; // cut first half cleanly
ListNode first = head;
// Step 3: merge alternately
while (second != null) {
ListNode tmp1 = first.next;
ListNode tmp2 = second.next;
first.next = second;
second.next = tmp1;
first = tmp1;
second = tmp2;
}
}
private ListNode reverse(ListNode head) {
ListNode prev = null, curr = head;
while (curr != null) {
ListNode next = curr.next;
curr.next = prev;
prev = curr;
curr = next;
}
return prev;
}Input: 1 β 2 β 3 β 4 β 5
Step 1: middle = node(3)
Step 2: reverse [4,5] β 5 β 4. cut: first=[1,2,3], second=[5,4]
Step 3: merge:
1β5β2β3, tmp1=2, tmp2=4
2β4β3, tmp1=3, tmp2=null β done
Output: 1 β 5 β 2 β 4 β 3 β
LeetCode #148 | Difficulty: Medium | Company: Amazon, Google | Category: Reversal as Tool (Merge Sort)
Sort a linked list in O(n log n) time and O(1) space using merge sort.
Bottom-up merge sort on linked list. Find middle (split point), sort each half recursively, then merge. The reversal pattern's "find middle" technique enables O(1) space.
public ListNode sortList(ListNode head) {
if (head == null || head.next == null) return head;
// Find middle and split
ListNode slow = head, fast = head.next; // fast=head.next β left-middle
while (fast != null && fast.next != null) {
slow = slow.next;
fast = fast.next.next;
}
ListNode second = slow.next;
slow.next = null; // cut
// Sort both halves
ListNode left = sortList(head);
ListNode right = sortList(second);
// Merge
return merge(left, right);
}
private ListNode merge(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0), curr = dummy;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) { curr.next = l1; l1 = l1.next; }
else { curr.next = l2; l2 = l2.next; }
curr = curr.next;
}
curr.next = (l1 != null) ? l1 : l2;
return dummy.next;
}Input: 4 β 2 β 1 β 3
Split: [4,2] and [1,3]
Sort: [2,4] and [1,3]
Merge: 1 β 2 β 3 β 4 β
Time: O(n log n), Space: O(log n) recursion stack
LeetCode #19 | Difficulty: Medium | Company: Amazon, Microsoft | Category: Two-Pointer Gap
Remove the nth node from the end of the list in one pass.
Gap technique: advance fast pointer n+1 steps ahead. When fast reaches null, slow is one node before the target. slow.next = slow.next.next removes the target.
public ListNode removeNthFromEnd(ListNode head, int n) {
ListNode dummy = new ListNode(0);
dummy.next = head;
ListNode slow = dummy, fast = dummy;
// Advance fast n+1 steps (so slow lands BEFORE the target)
for (int i = 0; i <= n; i++) fast = fast.next;
// Move both until fast reaches null
while (fast != null) {
slow = slow.next;
fast = fast.next;
}
// slow is one node before the nth-from-end
slow.next = slow.next.next;
return dummy.next;
}Input: 1 β 2 β 3 β 4 β 5, n=2
fast advances n+1=3 steps: fast=node(3)
Move until fast=null:
slow=1, fast=4 β slow=2, fast=5 β slow=3, fast=null
slow.next = slow.next.next β remove node(4)
Output: 1 β 2 β 3 β 5 β
LeetCode #2 | Difficulty: Medium | Company: Amazon, Google, Microsoft | Category: LinkedList Simulation
Two non-empty linked lists represent non-negative integers in reverse order. Add them and return result as linked list.
Traverse both lists simultaneously, add digit by digit with carry. Build result list. Handle remaining carry at end.
public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
int carry = 0;
while (l1 != null || l2 != null || carry != 0) {
int sum = carry;
if (l1 != null) { sum += l1.val; l1 = l1.next; }
if (l2 != null) { sum += l2.val; l2 = l2.next; }
carry = sum / 10;
curr.next = new ListNode(sum % 10);
curr = curr.next;
}
return dummy.next;
}l1 = 2 β 4 β 3 (represents 342)
l2 = 5 β 6 β 4 (represents 465)
pos0: 2+5=7, carry=0 β node(7)
pos1: 4+6=10, carry=1 β node(0)
pos2: 3+4+1=8, carry=0 β node(8)
Output: 7 β 0 β 8 (represents 807 = 342+465) β
LeetCode #138 | Difficulty: Medium | Company: Amazon, Facebook, Google | Category: LinkedList Clone
Deep copy a linked list where each node has a
nextand arandompointer.
HashMap approach: map each original node to its clone. First pass: create all clone nodes. Second pass: set next and random pointers using the map.
public Node copyRandomList(Node head) {
if (head == null) return null;
Map<Node, Node> map = new HashMap<>();
// Pass 1: create all clone nodes
Node curr = head;
while (curr != null) {
map.put(curr, new Node(curr.val));
curr = curr.next;
}
// Pass 2: set next and random pointers
curr = head;
while (curr != null) {
if (curr.next != null) map.get(curr).next = map.get(curr.next);
if (curr.random != null) map.get(curr).random = map.get(curr.random);
curr = curr.next;
}
return map.get(head);
}public Node copyRandomList(Node head) {
if (head == null) return null;
// Step 1: interleave clones β A β A' β B β B' β ...
Node curr = head;
while (curr != null) {
Node clone = new Node(curr.val);
clone.next = curr.next;
curr.next = clone;
curr = clone.next;
}
// Step 2: set random pointers for clones
curr = head;
while (curr != null) {
if (curr.random != null)
curr.next.random = curr.random.next;
curr = curr.next.next;
}
// Step 3: separate the two lists
Node dummy = new Node(0);
Node cloneCurr = dummy;
curr = head;
while (curr != null) {
cloneCurr.next = curr.next;
curr.next = curr.next.next;
cloneCurr = cloneCurr.next;
curr = curr.next;
}
return dummy.next;
}Original: 1 β 2 β 3
random: 1.random=3, 2.random=1, 3.random=2
After pass 1 (HashMap): map={1:1', 2:2', 3:3'}
After pass 2: 1'.next=2', 1'.random=3', 2'.next=3', 2'.random=1', etc.
Output: deep copy with all pointers correctly mapped β
LeetCode #21 | Difficulty: Easy | Company: Amazon, Microsoft, Google | Category: LinkedList Merge
Merge two sorted linked lists and return the merged list.
Dummy head approach. Compare heads of both lists, attach smaller node to result, advance that pointer. Attach remaining list at end.
public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
ListNode dummy = new ListNode(0);
ListNode curr = dummy;
while (l1 != null && l2 != null) {
if (l1.val <= l2.val) { curr.next = l1; l1 = l1.next; }
else { curr.next = l2; l2 = l2.next; }
curr = curr.next;
}
curr.next = (l1 != null) ? l1 : l2; // attach remaining
return dummy.next;
}l1 = 1 β 2 β 4
l2 = 1 β 3 β 4
1β€1 β take l1(1). l1=2β4
1β€3 β take l2(1). l2=3β4? No: l1.val=2 > l2.val=1 β take l2(1). l2=3β4
2β€3 β take l1(2). l1=4
3β€4 β take l2(3). l2=4
4β€4 β take l1(4). l1=null
Attach l2: 4βnull
Output: 1 β 1 β 2 β 3 β 4 β 4 β
| Problem | Category | Key technique |
|---|---|---|
| Reverse LinkedList | Full Reversal | prev=null; 4-line flip; return prev |
| Reverse Sub-list | Partial | walk to p-1; save tail; reverse (q-p+1); reconnect |
| Reverse in Pairs | k=2 Group | dummy; swap adjacent pairs; prevTail = first |
| Reverse K-Group | K-Group | check k exist; save tail; reverse; reconnect; repeat |
| Reverse Even Groups | Conditional | count actual group size; reverse only if even |
| Rotate List | Reconnect | find len+tail; k%=len; connect tailβhead; break at len-k |
| Reverse Alternate K | K-Group + Skip | reverse k; skip k; repeat |
| Palindrome LL | Reversal Tool | find mid; reverse half; compare; restore |
| Reorder List | Reversal Tool | find mid; reverse half; merge alternately |
| Sort List | Reversal Tool | find mid; split; sort; merge (merge sort) |
| Remove Nth From End | Gap Technique | dummy; fast n+1 ahead; slow lands before target |
| Add Two Numbers | Simulation | digit-by-digit with carry; dummy head |
| Copy Random Pointer | HashMap / Interleave | map origβclone; set pointers; or interleave+separate |
| Merge Two Sorted | Merge | dummy; compare heads; attach smaller; append rest |