Problem
Given a linked list and an integer k, shift every node k positions to the right โ nodes that fall off the tail wrap around to the front. If k is larger than the list length, only the remainder after dividing by the length matters.
[1,2,3,4,5]
- Input: head = [1,2,3,4,5], k = 2
- Output: [4,5,1,2,3]
- Explanation: The last 2 nodes move to the front, pushing the others to the right.
A second example shows why reducing k matters:
- Input: head = [0,1,2], k = 4
- Output: [2,0,1]
- Explanation: 4 % 3 = 1 effective rotation; only the last node moves to the front.
Intuition
A right-rotation by k is the same as taking the last k nodes and prepending them to the front. The trick is that rotating a list of length L by L is the same as doing nothing, so only k % L rotations actually matter. Once we know the effective count, we need to find where the new tail is โ everything before it stays put, everything after it jumps to the front.
Solution โ Circle and Cut
Connect the list into a ring, locate the new tail (L โ k positions from the head), and break the circle there.
- Walk to the end of the list to get both the length L and a pointer to the tail
- Compute the effective rotation:
k_eff = k % L; if it is 0, return head unchanged - Close the list into a ring by linking tail back to head
- Advance
L โ k_eff โ 1steps from head to reach the new tail - Save
new_tail.nextas the new head, then setnew_tail.next = Noneto break the ring - Return the new head
1class Solution:
2 def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
3 if not head or not head.next or k == 0:
4 return head
5
6 # find length and the tail in one pass
7 length = 1
8 tail = head
9 while tail.next:
10 length += 1
11 tail = tail.next
12
13 k_eff = k % length
14 if k_eff == 0: # rotating by a multiple of length is a no-op
15 return head
16
17 tail.next = head # close the ring
18
19 # new tail sits L - k_eff positions from the head (1-indexed)
20 # so advance L - k_eff - 1 steps
21 new_tail = head
22 for _ in range(length - k_eff - 1):
23 new_tail = new_tail.next
24
25 new_head = new_tail.next # first node of the rotated suffix
26 new_tail.next = None # cut the ring to re-form a linear list
27 return new_headTime: O(L) โ one pass to find the length and tail, then at most one more pass to locate the new tail.
Space: O(1) โ only a handful of pointers; the list nodes are rearranged in place.
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Circle and Cut | O(L) | O(1) | Always โ this is the canonical one-pass solution |
Common Mistakes
- Skipping
k = k % Lโ a value of k larger than L (e.g. k=1,000,000 on a 5-node list) would advance the pointer far past the end of the (now-circular) list without the modulo reduction, reaching the wrong position. - Advancing L โ k steps instead of L โ k โ 1 โ this puts the pointer on the new head, not the new tail, so
new_tail.nextpoints to the node after the new head rather than the new head itself. - Forgetting to break the ring โ after cutting the list,
new_tail.nextmust be set to null; leavingtail.next = headintact turns the returned list into an infinite cycle. - Returning
headwhen k equals 0 only before the modulo โ k=5 on a 5-node list reduces to 0 after the modulo and also requires an early return; a check before modulo alone will miss this and may produce a wrong result when the loop runs 0 iterations but the ring is never broken. - Not guarding against a one-node list โ if
head.nextis null, dividing by length works (length=1, kEff=0), but closing the ring setshead.next = headand the loop then steps into an infinite cycle if the early-return check is absent.
Related Problems
remove-nth-node-from-end-of-listโ also finds a node a fixed number of positions from the end before relinkingmiddle-of-the-linked-listโ uses list length to target a specific position, the same sub-problem solved hereodd-even-linked-listโ splits a list into two groups and reconnects the tail of one to the head of the otherrotate-arrayโ the same right-rotation operation on arrays, solved with in-place reversalsreorder-listโ multi-step list restructuring: find a midpoint, reverse a half, then interleave