Rotate List
MedPrompt
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:
- The number of nodes in the list is in the range
[0, 500]. -100 <= Node.val <= 1000 <= k <= 2 * 109
Approaches
2 approaches with complexity analysis and trade-offs.
This approach simulates the rotation process directly. We rotate the list to the right by one position and repeat this operation k times. A key optimization is to first calculate the effective number of rotations, k % n, where n is the length of the list, to handle large values of k.
Algorithm
- If
headis null,head.nextis null, orkis 0, returnhead. - Calculate the length of the list,
n. - Calculate
k = k % n. Ifk == 0, returnhead. - Repeat
ktimes:- Traverse to the end of the list to find the last node (
last) and the second-to-last node (secondLast). - Set
secondLast.next = null. - Set
last.next = head. - Update
head = last.
- Traverse to the end of the list to find the last node (
- Return
head.
Walkthrough
The core idea is to perform the rotation one step at a time. To rotate the list to the right by one, we need to move the last element to the front. This involves finding the last and second-to-last nodes, making the last node the new head, and adjusting the pointers accordingly. This entire process is repeated k times.
To avoid unnecessary rotations when k is larger than the list length n, we first compute the effective number of rotations as k' = k % n. If k' is 0, the list remains unchanged. Otherwise, we perform the single-step rotation k' times.
Here is the algorithm:
- Handle edge cases: an empty list, a single-node list, or
k=0. - Calculate the list's length,
n. - Compute
k = k % n. Ifkis 0, return the original list. - Loop
ktimes: a. Find the last node and its predecessor (the second-to-last node). b. Set thenextof the second-to-last node tonull. c. Set thenextof the last node to the current head. d. Update the head to be the last node. - Return the modified head.
/** * 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; } // Find the length of the list int n = 1; ListNode current = head; while (current.next != null) { current = current.next; n++; } // Calculate effective rotations k = k % n; if (k == 0) { return head; } // Rotate k times for (int i = 0; i < k; i++) { ListNode last = head; ListNode secondLast = null; while (last.next != null) { secondLast = last; last = last.next; } if (secondLast != null) { secondLast.next = null; last.next = head; head = last; } } return head; }}Complexity
Time
O(n * (k % n))
Space
O(1)
Trade-offs
Pros
Conceptually simple and easy to understand.
Cons
Very inefficient, as it requires traversing the list
ktimes.Leads to Time Limit Exceeded on most platforms for large
korn.
This efficient approach avoids repeated traversals by first making the linked list circular. After determining the length n, we connect the tail to the head. Then, we calculate the position of the new tail, which is n - (k % n) - 1 nodes from the beginning. We traverse to this new tail, break the link after it, and the next node becomes the new head.
Algorithm
- Handle edge cases: if
headis null,head.nextis null, orkis 0, returnhead. - Traverse the list to find its length
nand thetailnode. - Calculate
k = k % n. Ifk == 0, no rotation is needed, so returnhead. - Make the list circular by setting
tail.next = head. - Calculate the position of the new tail:
steps = n - k - 1. - Traverse
stepsfrom the head to find thenewTailnode. - The
newHeadisnewTail.next. - Break the circular link:
newTail.next = null. - Return
newHead.
Walkthrough
Instead of rotating one element at a time, we can solve this problem by rearranging pointers in a more direct way. The key insight is that rotating the list k times to the right is equivalent to taking the last k nodes and moving them to the front.
The steps are as follows:
- First, traverse the list to find its length,
n, and its tail node. - Handle edge cases: if the list is empty, has one node, or
kis 0, return the head. - Calculate the effective rotations
k = k % n. Ifkis 0, the list is unchanged, so we can return the head. - Make the list circular by connecting the
nextpointer of the tail node to the head node. - Now that we have a circular list, we need to find the new head and new tail. The last
knodes will form the new beginning of the list. This means the new tail is the node at positionn - k - 1(0-indexed) from the original head. - We traverse
n - k - 1steps from the head to locate thenewTail. - The
newHeadis the node immediately followingnewTail. - To finalize the new list, we break the circular link by setting
newTail.nexttonull. - Finally, we return the
newHead.
/** * 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; } // 1. Find the length and the tail node int n = 1; ListNode tail = head; while (tail.next != null) { tail = tail.next; n++; } // Calculate effective rotations k = k % n; if (k == 0) { return head; // No rotation needed } // 2. Connect the tail to the head to form a circle tail.next = head; // 3. Find the new tail. It's at position (n - k - 1) int stepsToNewTail = n - k - 1; ListNode newTail = head; for (int i = 0; i < stepsToNewTail; i++) { newTail = newTail.next; } // 4. The new head is the node after the new tail ListNode newHead = newTail.next; // 5. Break the circle newTail.next = null; return newHead; }}Complexity
Time
O(n)
Space
O(1)
Trade-offs
Pros
Highly efficient with a time complexity linear to the list size.
Uses constant extra space.
Handles all edge cases including very large
kvalues gracefully.
Cons
Temporarily modifies the list structure by making it circular, which might be a consideration in a multi-threaded environment without proper locking.
Solutions
Solution
/** * Definition for singly-linked list. * public class ListNode { * public int val; * public ListNode next; * public ListNode(int val=0, ListNode next=null) { * this.val = val; * this.next = next; * } * } */ public class Solution { public ListNode RotateRight ( ListNode head , int k ) { if ( head == null || head . next == null ) { return head ; } var cur = head ; int n = 0 ; while ( cur != null ) { cur = cur . next ; ++ n ; } k %= n ; if ( k == 0 ) { return head ; } var fast = head ; var slow = head ; while ( k -- > 0 ) { fast = fast . next ; } while ( fast . next != null ) { fast = fast . next ; slow = slow . next ; } var ans = slow . next ; slow . next = null ; fast . next = head ; return ans ; } }/** * 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 ) { return head ; } ListNode cur = head ; int n = 0 ; for (; cur != null ; cur = cur . next ) { n ++; } k %= n ; if ( k == 0 ) { return head ; } ListNode fast = head ; ListNode slow = head ; while ( k -- > 0 ) { fast = fast . next ; } while ( fast . next != null ) { fast = fast . next ; slow = slow . next ; } ListNode ans = slow . next ; slow . next = null ; fast . next = head ; return ans ; } }/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode() : val(0), next(nullptr) {} * ListNode(int x) : val(x), next(nullptr) {} * ListNode(int x, ListNode *next) : val(x), next(next) {} * }; */ class Solution { public: ListNode * rotateRight ( ListNode * head , int k ) { if ( ! head || ! head -> next ) { return head ; } ListNode * cur = head ; int n = 0 ; while ( cur ) { ++ n ; cur = cur -> next ; } k %= n ; if ( k == 0 ) { return head ; } ListNode * fast = head ; ListNode * slow = head ; while ( k -- ) { fast = fast -> next ; } while ( fast -> next ) { fast = fast -> next ; slow = slow -> next ; } ListNode * ans = slow -> next ; slow -> next = nullptr ; fast -> next = head ; return ans ; } };# 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 head is None or head . next is None : return head cur , n = head , 0 while cur : n += 1 cur = cur . next k %= n if k == 0 : return head fast = slow = head for _ in range ( k ): fast = fast . next while fast . next : fast , slow = fast . next , slow . next ans = slow . next slow . next = None fast . next = head return ansVideo walkthrough
Newsletter
One sharp idea, every week
System design and interview prep — short enough to finish.
No spam. Unsubscribe anytime.
Practice
Same difficulty — related problems to reinforce the pattern.