61. Rotate List - Explanation

Problem Link

Description

You are 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,6], k = 3

Output: [4,5,6,1,2,3]

Explanation:
Rotate 1: [6,1,2,3,4,5]
Rotate 2: [5,6,1,2,3,4]
Rotate 3: [4,5,6,1,2,3]

Example 2:

Input: head = [0,1,2], k = 4

Output: [2,0,1]

Explanation:
Rotate 1: [2,0,1]
Rotate 2: [1,2,0]
Rotate 3: [0,1,2]
Rotate 4: [2,0,1]

Constraints:

  • 0 <= Length of the list <= 500.
  • -100 <= Node.val <= 100
  • 0 <= k <= 2,000,000,000


Topics

Company Tags

Please upgrade to NeetCode Pro to view company tags.



Prerequisites

Before attempting this problem, you should be comfortable with:

  • Linked List Fundamentals - Understanding node structure, traversal, and how to find the length of a list
  • Pointer Manipulation - Reconnecting nodes by changing next pointers to restructure the list
  • Modular Arithmetic - Using modulo to normalize rotation count when it exceeds list length
  • Circular Linked List - The technique of connecting tail to head to form a cycle, then breaking it at the new position

1. Convert To Array

Intuition

The challenge with linked lists is that we cannot directly access elements by index. One straightforward approach is to convert the list to an array, perform the rotation using array indexing, and then write the values back to the list nodes. This trades memory for simplicity, allowing us to use familiar array rotation logic.

Algorithm

  1. If the list is empty, return null.
  2. Traverse the list and store all node values in an array.
  3. Compute k = k % n to handle rotations larger than the list length.
  4. Traverse the list again, assigning values from the rotated positions:
    • First, assign the last k values from the array.
    • Then, assign the remaining values.
  5. Return the head of the modified list.
# 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:
            return None

        arr, cur = [], head
        while cur:
            arr.append(cur.val)
            cur = cur.next

        n = len(arr)
        k %= n
        cur = head
        for i in range(n - k, n):
            cur.val = arr[i]
            cur = cur.next

        for i in range(n - k):
            cur.val = arr[i]
            cur = cur.next

        return head

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(n)O(n)

2. Iteration

Intuition

Rotating a linked list by k means moving the last k nodes to the front. We can do this by finding the new tail (the node at position n - k - 1), breaking the list there, and reconnecting the old tail to the old head. The key insight is that we only need to find two positions: where to break the list and where to reconnect.

Algorithm

  1. If the list is empty, return null.
  2. Traverse the list to find its length and the tail node.
  3. Compute k = k % length. If k == 0, no rotation is needed.
  4. Traverse to the node at position length - k - 1 (this will be the new tail).
  5. Set the new head to be the next node after the new tail.
  6. Break the link by setting the new tail's next to null.
  7. Connect the old tail to the old head.
  8. Return the new head.
# 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: ListNode, k: int) -> ListNode:
        if not head:
            return head

        length, tail = 1, head
        while tail.next:
            tail = tail.next
            length += 1

        k = k % length
        if k == 0:
            return head

        cur = head
        for i in range(length - k - 1):
            cur = cur.next
        newHead = cur.next
        cur.next = None
        tail.next = head

        return newHead

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

3. Iteration (Using One Pointer)

Intuition

We can simplify the two-pointer approach by first creating a circular list. Connect the tail to the head, then traverse n - k steps from the tail to find the new tail. Break the circle at that point. This approach uses a single pointer and avoids the need to track both the tail and find the break point separately.

Algorithm

  1. If the list is empty, return null.
  2. Traverse to find the tail and count the length n.
  3. Connect the tail to the head, forming a circular list.
  4. Compute k = k % n to handle large values of k.
  5. Move n - k steps from the current position (the tail) to reach the new tail.
  6. The new head is the node after the new tail.
  7. Break the circle by setting the new tail's next to null.
  8. Return the new head.
# 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: ListNode, k: int) -> ListNode:
        if not head:
            return head

        cur, n = head, 1
        while cur.next:
            n += 1
            cur = cur.next

        cur.next = head
        k %= n
        for i in range(n - k):
            cur = cur.next

        head = cur.next
        cur.next = None
        return head

Time & Space Complexity

  • Time complexity: O(n)O(n)
  • Space complexity: O(1)O(1) extra space.

Common Pitfalls

Not Handling Empty List or Single Node

Forgetting to check if the list is empty (head == null) or has only one node causes null pointer exceptions. A single-node list rotated by any amount remains unchanged, but the code must handle this edge case explicitly.

Forgetting to Normalize k by List Length

When k is larger than the list length or equals it, the rotation results in the same list. Failing to compute k = k % length before rotation leads to unnecessary traversals or incorrect results. Additionally, when k % length == 0, no rotation is needed and the original head should be returned.

Incorrectly Breaking and Reconnecting the List

When creating the new list structure, forgetting to set the new tail's next to null creates a cycle in the linked list. Similarly, forgetting to connect the old tail to the old head leaves the list disconnected. Both pointer updates are essential for correct rotation.