Swapping Nodes in a Linked List — Two-Pointer Value Swap Explained
Advertisement
Problem Statement
LeetCode 1721 — Swapping Nodes in a Linked List Difficulty: Medium | Pattern: Two Pointers
You are given the head of a linked list and an integer k. Return the head of the linked list after swapping the values of the kth node from the beginning and the kth node from the end (the list is 1-indexed).
Constraints:
- Number of nodes:
1 <= n <= 5 * 10^4 1 <= Node.val <= 1001 <= k <= n
Example 1:
Input: head = [1, 2, 3, 4, 5], k = 2
Output: [1, 4, 3, 2, 5]
Explanation: 2nd from start is node(2), 2nd from end is node(4). Swap values.Example 2:
Input: head = [7, 9, 6, 6, 7, 8, 3, 0, 9, 5], k = 5
Output: [7, 9, 6, 6, 8, 7, 3, 0, 9, 5]Example 3:
Input: head = [1], k = 1
Output: [1]
Explanation: Both pointers point to the same node. Swap is a no-op.Why This Problem Matters
This problem is a beautiful combination of two classic linked list techniques: finding the kth node from the beginning and finding the kth node from the end. Amazon and Bloomberg use it as a warm-up or mid-tier interview question to test whether a candidate truly understands the two-pointer technique versus mechanically memorizing it.
What makes this problem elegant is that you do not need to swap the nodes structurally. Swapping node values is sufficient — and this insight alone cuts the implementation complexity in half. Structural swaps in linked lists require careful pointer rewiring; value swaps are always simple and virtually bug-free.
The underlying challenge — finding the kth node from the end without knowing the list length — is a fundamental linked list technique that appears in "Remove Nth Node From End" (LC 19), "Middle of Linked List" (LC 876), and many other problems. Mastering the offset-pointer approach here pays dividends across the entire linked list problem set.
This problem also appears in the Amazon LeetCode OA (online assessment) list and Bloomberg phone screens as a question that requires clean one-pass logic under time pressure.
The Core Insight
There are two ways to think about this:
Approach 1 — Two passes: Walk the list once to find its length n, compute positions, then make a second pass to locate both nodes. Swap values.
Approach 2 — One pass with three pointers (the elegant interview answer):
- Walk a pointer
firstto thekth node from the start. - Start a second pointer
secondat the head and a third pointerrunneratfirst. - Advance both
secondandrunnertogether untilrunner.nextis null. - Now
secondis exactly at the kth node from the end. - Swap the values of
firstandsecond.
This works because when runner (starting from first) reaches the last node, second (starting from head) has advanced the same number of steps — exactly n - k steps — landing at position k from the end.
Visual Dry Run
Input: [1, 2, 3, 4, 5], k = 2
| Phase | first | second | runner |
|---|---|---|---|
| Advance first k=2 steps | node(2) | head | node(2) |
| runner starts at first | node(2) | ||
| Walk second+runner together | node(2) | node(3) | |
| node(3) | node(4) | ||
| node(4) | node(5) — runner.next is null, stop | ||
| Swap values | first.val=2 becomes 4 | second.val=4 becomes 2 |
Result: [1, 4, 3, 2, 5]
Solution (Optimal)
from typing import Optional
class ListNode:
def __init__(self, val=0, next=None):
self.val = val
self.next = next
def swapNodes(head: Optional[ListNode], k: int) -> Optional[ListNode]:
# Step 1: Advance 'first' to the kth node from the beginning
first = head
for _ in range(k - 1):
first = first.next
# Step 2: Use two pointers to find kth from end
second = head
runner = first # runner starts at first, not at head
while runner.next:
runner = runner.next
second = second.next
# Step 3: Swap values only (no pointer rewiring needed)
first.val, second.val = second.val, first.val
return headfunction swapNodes(head, k) {
// Step 1: Find kth node from the beginning
let first = head;
for (let i = 1; i < k; i++) {
first = first.next;
}
// Step 2: Use two pointers to find kth from end
let second = head;
let runner = first;
while (runner.next !== null) {
runner = runner.next;
second = second.next;
}
// Step 3: Swap values
const temp = first.val;
first.val = second.val;
second.val = temp;
return head;
}Complexity:
| Metric | Value |
|---|---|
| Time | O(n) — single pass |
| Space | O(1) — three pointers only |
Common Mistakes
- Trying to swap nodes instead of values: Structural node swaps in a singly linked list require tracking predecessor pointers on both sides — unnecessarily complex when the problem only needs the head returned with swapped values.
- Off-by-one in advancing to kth node: The loop should run
k - 1times starting fromhead(since head is already at position 1), notktimes. - Moving runner one extra step: The while condition must be
runner.next != null, notrunner != null. Stopping whenrunner.nextis null ensuressecondlands exactly at the kth-from-end node. - Not handling the same-node case: When k equals the middle position (e.g., n=5, k=3), first and second point to the same node. Swapping with itself is a no-op and the code handles it correctly without a special case.
- Starting runner at head instead of first: Runner must start at
first, not athead, so that the distance it travels equalsn - ksteps.
Interview Tips
- Lead with the key insight: "I'll swap values, not nodes — this avoids all pointer rewiring and makes the code much simpler."
- Name your pointers clearly: Use
first,second, andrunner— notp,q,r. Clear names help both you and the interviewer follow along. - Confirm the same-node edge case: "If first and second point to the same node, swapping with itself is a no-op — my code handles this without a special case."
- Offer the two-pass alternative: Mention that you could find the length first, then compute the position. But the single-pass approach is more elegant and preferred.
- Discuss when value swap fails: If nodes held complex objects and structural reordering mattered, you would need to rewire pointers. Ask the interviewer whether value swap suffices.
Follow-up Questions
- LeetCode 24 — Swap Nodes in Pairs: Structurally swap every two adjacent nodes — here you cannot avoid pointer rewiring.
- What if you must swap the nodes structurally? Walk through the four-pointer rewiring needed in a singly linked list, tracking predecessors of both nodes.
- Generalize to swapping a range: Swap the first k nodes with the last k nodes as complete sublists.
- LeetCode 19 — Remove Nth Node From End: Same two-pointer offset technique for finding the predecessor of the nth-from-end node.
- What if the list is doubly linked? The value swap logic is identical. Structural swap becomes simpler because you have
prevpointers. - Can you solve it without knowing the length? Yes — this solution is already O(n) in a single pass without computing list length.
Key Takeaways
- Swapping values instead of nodes eliminates all pointer rewiring and makes the code much simpler — always consider this first.
- The offset pointer technique (advance
runnerto the kth node, then walksecondandrunnertogether) finds the kth-from-end node in one pass without knowing list length. - Three pointers —
first,second,runner— are all you need for an O(n), O(1) solution. - The kth-from-end pointer pattern appears in LC 19 (Remove Nth Node) and LC 876 (Middle of Linked List).
- When
firstandsecondpoint to the same node, the swap is a harmless no-op — no special case is required. - This problem is a clean example of why interviewers ask linked list questions: pointer discipline and edge case awareness are immediately visible in the code.
Advertisement