Swapping Nodes in a Linked List — Two-Pointer Value Swap Explained

Sanjeev SharmaSanjeev Sharma
7 min read

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 <= 100
  • 1 <= 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):

  1. Walk a pointer first to the kth node from the start.
  2. Start a second pointer second at the head and a third pointer runner at first.
  3. Advance both second and runner together until runner.next is null.
  4. Now second is exactly at the kth node from the end.
  5. Swap the values of first and second.

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

Phasefirstsecondrunner
Advance first k=2 stepsnode(2)headnode(2)
runner starts at firstnode(2)
Walk second+runner togethernode(2)node(3)
node(3)node(4)
node(4)node(5) — runner.next is null, stop
Swap valuesfirst.val=2 becomes 4second.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 head
function 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:

MetricValue
TimeO(n) — single pass
SpaceO(1) — three pointers only

Common Mistakes

  1. 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.
  2. Off-by-one in advancing to kth node: The loop should run k - 1 times starting from head (since head is already at position 1), not k times.
  3. Moving runner one extra step: The while condition must be runner.next != null, not runner != null. Stopping when runner.next is null ensures second lands exactly at the kth-from-end node.
  4. 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.
  5. Starting runner at head instead of first: Runner must start at first, not at head, so that the distance it travels equals n - k steps.

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, and runner — not p, 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

  1. LeetCode 24 — Swap Nodes in Pairs: Structurally swap every two adjacent nodes — here you cannot avoid pointer rewiring.
  2. 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.
  3. Generalize to swapping a range: Swap the first k nodes with the last k nodes as complete sublists.
  4. LeetCode 19 — Remove Nth Node From End: Same two-pointer offset technique for finding the predecessor of the nth-from-end node.
  5. What if the list is doubly linked? The value swap logic is identical. Structural swap becomes simpler because you have prev pointers.
  6. 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 runner to the kth node, then walk second and runner together) 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 first and second point 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

Sanjeev Sharma

Written by

Sanjeev Sharma

Full Stack Engineer · E-mopro

Related reading