Definition
Walk to the node just before position p, reverse exactly q-p+1 nodes using the three-pointer technique, then re-stitch the reversed segment back to the node before p and to the node after q. The untouched prefix and suffix keep their links.
In Rajesh's chain of transaction slips, only the slips from the third to the fifth need to be read in reverse while the rest stay as they are. The clerk holds the slip just before the third, flips only that middle run, then clips the flipped run back onto the slip before it and onto the slip after it.
Understanding the Concepts
What is the problem?
Reverse a Sub-list (Reverse Nodes Between Positions p and q). Given the head of a singly linked list and two positions p and q (1-based, p <= q), reverse the nodes from position p to position q in place and return the head. Do it in a single pass with O(1) extra space.
How does the approach work?
Use a dummy node before the head so that reversing from position 1 needs no special case. Advance a pointer beforeP by p-1 steps so it sits just before the segment. Let segStart be beforeP.next, the first node of the segment, which will become the segment's tail after reversal. Then reverse q-p+1 nodes with the standard three-pointer loop. Finally re-stitch: beforeP.next points to the new segment head (previous), and segStart.next points to the node that follows the segment (current).
For example reversing positions 2 to 4 of 1 -> 2 -> 3 -> 4 -> 5 gives 1 -> 4 -> 3 -> 2 -> 5. The dummy makes the p=1 case fall out naturally because beforeP is the dummy.
A senior-level nuance is the re-stitching order and the role of segStart: because segStart is the original first node of the run, after reversal it is the run's last node, so its next is exactly where the suffix must attach. Getting these two reconnections right is the entire difficulty; the reversal itself is the easy part you already know from full-list reversal.
What is the banking use case?
The code contains a SlipNode, a DisputeView with reverseBetween(head, p, q), and a demo.
How do you implement this in Java?
// ─── File: src/main/java/com/bank/dispute/SlipNode.java ───
package com.bank.dispute;
public class SlipNode {
final int id;
SlipNode next;
SlipNode(int id) { this.id = id; }
}
// ─── File: src/main/java/com/bank/dispute/DisputeView.java ───
package com.bank.dispute;
public class DisputeView {
public SlipNode reverseBetween(SlipNode head, int p, int q) {
if (head == null || p == q) return head;
SlipNode dummy = new SlipNode(-1);
dummy.next = head;
SlipNode beforeP = dummy;
for (int i = 0; i < p - 1; i++) beforeP = beforeP.next; // node before position p
SlipNode segStart = beforeP.next; // becomes the segment TAIL after reversal
SlipNode previous = null, current = segStart;
for (int i = 0; i < q - p + 1; i++) { // reverse exactly q-p+1 nodes
SlipNode next = current.next;
current.next = previous;
previous = current;
current = next;
}
beforeP.next = previous; // prefix → new segment head
segStart.next = current; // segment tail → suffix
return dummy.next;
}
}
// ─── File: src/main/java/com/bank/dispute/SublistDemo.java ───
package com.bank.dispute;
import java.util.logging.Logger;
public class SublistDemo {
private static final Logger log = Logger.getLogger(SublistDemo.class.getName());
public static void main(String[] args) {
SlipNode head = build(new int[]{1, 2, 3, 4, 5});
log.info("Original: " + render(head));
SlipNode out = new DisputeView().reverseBetween(head, 2, 4);
log.info("Reversed positions 2..4: " + render(out));
}
static SlipNode build(int[] ids) {
SlipNode d = new SlipNode(-1), t = d;
for (int id : ids) { t.next = new SlipNode(id); t = t.next; }
return d.next;
}
static String render(SlipNode n) {
StringBuilder sb = new StringBuilder();
while (n != null) { sb.append(n.id);
if (n.next != null) sb.append(" -> "); n = n.next; }
return sb.append(" -> null").toString();
}
}
What is the project structure?
dispute-sublist-reverser/
├── pom.xml
└── src/main/java/com/bank/dispute/
├── SublistDemo.java
├── SlipNode.java
└── DisputeView.java
How do you build and run?
# Build
mvn clean package -DskipTests
# Run
java -cp target/classes com.bank.dispute.SublistDemo
What is the step-by-step walkthrough?
Input data: chain 1 -> 2 -> 3 -> 4 -> 5, p=2, q=4.
beforeP advances p-1 = 1 step and lands on node 1. segStart is node 2, which will become the tail of the reversed run.q-p+1 = 3 nodes: 2, 3, 4. Internally this produces 4 -> 3 -> 2, with previous ending on node 4 and current ending on node 5.beforeP.next (node 1's next) becomes node 4, the new head of the run. segStart.next (node 2's next) becomes node 5, the suffix.1 -> 4 -> 3 -> 2 -> 5.Final output:
2026-10-27 19:25:42 [INFO] Original: 1 -> 2 -> 3 -> 4 -> 5 -> null
2026-10-27 19:25:42 [INFO] Reversed positions 2..4: 1 -> 4 -> 3 -> 2 -> 5 -> null
What is the high-level design?
═══ HLD — Dispute Window Reversal ═══
┌──────────┐ window ┌────────────────────┐ nodes ┌──────────────┐
│ Agent UI │───────→│ Dispute Svc ×2 │──────→│ slip chain │
└──────────┘ │ reverseBetween(p,q)│ │ (in memory) │
└────────────────────┘ └──────────────┘
What is the low-level design?
═══ LLD — DisputeView ═══
┌─ Key references ────────────────────────────────────┐
│ dummy → handles p=1 uniformly │
│ segStart → original head of run = tail after rev │
└──────────────────────────────────────────────────────┘
┌──────────────────────────────────────────┐
│ DisputeView │
│ + reverseBetween(head,p,q): SlipNode │ single pass, O(1)
└──────────────────────────────────────────┘
Contract for reverseBetween(head,p,q):
Pre: 1 ≤ p ≤ q ≤ length
Post: nodes [p..q] reversed; prefix/suffix intact
What is the time and space complexity?
Analyze the solution based on the algorithm used. Consider both the time to process input and the space required for any data structures.
What are common mistakes?
Common mistakes include off-by-one errors, not handling edge cases like empty input, and not considering the constraints of the problem.
What are the edge cases?
Edge cases include empty input, single element input, all identical elements, and boundary values.
What should a senior engineer know?
A senior engineer should understand the time-space tradeoffs, be able to explain the algorithm clearly, and know when this technique applies versus alternatives.
Visual Overview
Input: 1 -> 2 -> 3 -> 4 -> 5 (p=2, q=4)
│
▼
DisputeView.reverseBetween()
│ beforeP → node1, segStart = node2
│ reverse 3 nodes → 4 -> 3 -> 2
│ node1.next = 4 ; node2.next = 5
▼
Output: 1 -> 4 -> 3 -> 2 -> 5
Key Takeaway
Reversing a sublist between positions p and q is the full-list reversal with two added responsibilities: finding where to start and re-stitching the boundaries afterward. I place a dummy node before the head so that reversing from position one needs no special handling, then I walk a pointer p minus one steps so it rests on the node just before the segment. I remember the first node of the segment separately, because after reversal that original first node becomes the segment's tail, and its next pointer is exactly where the unchanged suffix must reattach.
I then run the familiar three-pointer reversal for exactly q minus p plus one nodes. The real work is the reconnection: the node before the segment now points to the new head of the reversed run, and the segment's original first node, now the tail, points to whatever followed the segment. The prefix and suffix are never touched, so the whole thing is one pass in constant space.
In my work at the National Bank of India this supported dispute review of Rajesh's transaction slips. The slips lived in a long linked chain, and a review needed a contiguous window shown in reverse chronological order while the surrounding slips kept their original order. Reaching the node before the window, flipping only the window in place, and carefully reconnecting both boundaries gave exactly that without allocating a second list.
Remember one sentence: understand the core algorithm and apply it to banking domain problems.
---