Losing head/tail while rewiring
Wrong move: Pointer updates overwrite references before they are saved.
Usually fails on: List becomes disconnected mid-operation.
Fix: Store next pointers first and use a dummy head for safer joins.
Move from brute-force thinking to an efficient approach using linked list strategy.
Given the head of a linked list, rotate the list to the right by k places.
Example 1:
Input: head = [1,2,3,4,5], k = 2 Output: [4,5,1,2,3]
Example 2:
Input: head = [0,1,2], k = 4 Output: [2,0,1]
Constraints:
[0, 500].-100 <= Node.val <= 1000 <= k <= 2 * 109Problem summary: Given the head of a linked list, rotate the list to the right by k places. Example 1: Input: head = [1,2,3,4,5], k = 2 Output: [4,5,1,2,3] Example 2: Input: head = [0,1,2], k = 4 Output: [2,0,1]
Start with the most direct exhaustive search. That gives a correctness anchor before optimizing.
Pattern signal: Linked List · Two Pointers
[1,2,3,4,5] 2
[0,1,2] 4
rotate-array)split-linked-list-in-parts)/**
* Definition for singly-linked list.
* public class ListNode {
* int val;
* ListNode next;
* ListNode() {}
* ListNode(int val) { this.val = val; }
* ListNode(int val, ListNode next) { this.val = val; this.next = next; }
* }
*/
class Solution {
public ListNode rotateRight(ListNode head, int k) {
if (head == null || head.next == null || k == 0) return head;
int len = 1;
ListNode tail = head;
while (tail.next != null) {
tail = tail.next;
len++;
}
k %= len;
if (k == 0) return head;
// Make circular then cut at new tail.
tail.next = head;
int stepsToNewTail = len - k;
ListNode newTail = head;
for (int i = 1; i < stepsToNewTail; i++) newTail = newTail.next;
ListNode newHead = newTail.next;
newTail.next = null;
return newHead;
}
}
/**
* type ListNode struct {
* Val int
* Next *ListNode
* }
*/
func rotateRight(head *ListNode, k int) *ListNode {
if head == nil || head.Next == nil || k == 0 {
return head
}
length := 1
tail := head
for tail.Next != nil {
tail = tail.Next
length++
}
k %= length
if k == 0 {
return head
}
tail.Next = head // Make circular.
steps := length - k
newTail := head
for i := 1; i < steps; i++ {
newTail = newTail.Next
}
newHead := newTail.Next
newTail.Next = nil
return newHead
}
# Definition for singly-linked list.
# class ListNode:
# def __init__(self, val=0, next=None):
# self.val = val
# self.next = next
class Solution:
def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if not head or not head.next or k == 0:
return head
length = 1
tail = head
while tail.next:
tail = tail.next
length += 1
k %= length
if k == 0:
return head
tail.next = head # Circular list.
steps = length - k
new_tail = head
for _ in range(steps - 1):
new_tail = new_tail.next
new_head = new_tail.next
new_tail.next = None
return new_head
/**
* Definition for singly-linked list.
* #[derive(PartialEq, Eq, Clone, Debug)]
* pub struct ListNode {
* pub val: i32,
* pub next: Option<Box<ListNode>>
* }
* impl ListNode {
* #[inline]
* fn new(val: i32) -> Self {
* ListNode { next: None, val }
* }
* }
*/
impl Solution {
pub fn rotate_right(head: Option<Box<ListNode>>, k: i32) -> Option<Box<ListNode>> {
let mut vals = Vec::new();
let mut cur = head;
while let Some(mut node) = cur {
vals.push(node.val);
cur = node.next.take();
}
let n = vals.len();
if n == 0 {
return None;
}
let k = (k as usize) % n;
if k == 0 {
return build_list(vals);
}
let mut rotated = Vec::with_capacity(n);
rotated.extend_from_slice(&vals[n - k..]);
rotated.extend_from_slice(&vals[..n - k]);
build_list(rotated)
}
}
fn build_list(vals: Vec<i32>) -> Option<Box<ListNode>> {
let mut head: Option<Box<ListNode>> = None;
for &v in vals.iter().rev() {
head = Some(Box::new(ListNode { val: v, next: head }));
}
head
}
/**
* Definition for singly-linked list.
* class ListNode {
* val: number
* next: ListNode | null
* constructor(val?: number, next?: ListNode | null) {
* this.val = (val===undefined ? 0 : val)
* this.next = (next===undefined ? null : next)
* }
* }
*/
function rotateRight(head: ListNode | null, k: number): ListNode | null {
if (!head || !head.next || k === 0) return head;
let len = 1;
let tail = head;
while (tail.next) {
tail = tail.next;
len++;
}
k %= len;
if (k === 0) return head;
tail.next = head; // Circular.
const steps = len - k;
let newTail = head;
for (let i = 1; i < steps; i++) newTail = newTail.next!;
const newHead = newTail.next;
newTail.next = null;
return newHead;
}
Use this to step through a reusable interview workflow for this problem.
Copy all n nodes into an array (O(n) time and space), then use array indexing for random access. Operations like reversal or middle-finding become trivial with indices, but the O(n) extra space defeats the purpose of using a linked list.
Most linked list operations traverse the list once (O(n)) and re-wire pointers in-place (O(1) extra space). The brute force often copies nodes to an array to enable random access, costing O(n) space. In-place pointer manipulation eliminates that.
Review these before coding to avoid predictable interview regressions.
Wrong move: Pointer updates overwrite references before they are saved.
Usually fails on: List becomes disconnected mid-operation.
Fix: Store next pointers first and use a dummy head for safer joins.
Wrong move: Advancing both pointers shrinks the search space too aggressively and skips candidates.
Usually fails on: A valid pair can be skipped when only one side should move.
Fix: Move exactly one pointer per decision branch based on invariant.