Given the head of a singly linked list and an integer k, rotate the linked list to the right by k places.
In a right rotation, the last node becomes the first node, and every remaining node moves one position toward the right. Return the head of the rotated linked list.
Example 1
Input: head = [1, 2, 3, 4, 5], k = 2
Output: [4, 5, 1, 2, 3]
Explanation: After one right rotation, list becomes [5, 1, 2, 3, 4]. After two right rotations, list becomes [4, 5, 1, 2, 3].
Example 2
Input: head = [0, 1, 2], k = 4
Output: [2, 0, 1]
Explanation: List length equals 3, so 4 % 3 = 1 effective right rotation gives [2, 0, 1].
Brute Force Approach
A right rotation can be performed by moving the last node of the linked list to the front. Since one such operation rotates the list by one position, repeating it k times gives the required result.
Before performing rotations, we first count the length of the linked list and reduce k using k % length. This avoids unnecessary full-cycle rotations because rotating a list by its length brings it back to the same order.
For every effective rotation, we traverse the list until the second last node, detach the last node, place it before the current head, and update the head pointer.
Algorithm
Return
headdirectly when the list is empty, has only one node, ork = 0, as none of these cases can produce a different ordering.Count the total number of nodes in the linked list, since the effective number of rotations depends on the list length.
Reduce the rotations using
k = k % length, as rotating the list by its full length brings it back to the original order.Repeat the rotation process
ktimes, with each iteration moving the last node to the front and therefore producing one right rotation.For each rotation, traverse the list until the second-last node, as this node is needed to detach the last node from the list.
Store the last node, set the second-last node's
nexttoNULL, and link the last node to the currenthead, since placing the last node before the head creates one right rotation.Update
headto the moved last node, as it now becomes the first node of the rotated list.Return the updated
headafter all effective rotations have been completed.
Dry Run
rotate list brute force
Solution
#include <bits/stdc++.h>using namespace std;struct ListNode { int data; Node* next; ListNode(int value) { data = value; next = nullptr; }};class Solution {public: /* Rotates the linked list to the right by k places */ ListNode* rotateRight(ListNode* head, int k) { // Handle empty list, single node, or zero rotations if (head == nullptr || head->next == nullptr || k == 0) { return head; } int length = 0; ListNode* temp = head; // Calculate total length of the list while (temp != nullptr) { length++; temp = temp->next; } // Remove redundant full cycles k = k % length; // Rotate the list one node at a time while (k > 0) { ListNode* secondLast = nullptr; ListNode* last = head; // Traverse to the end of the list while (last->next != nullptr) { secondLast = last; last = last->next; } // Move the last node to the front secondLast->next = nullptr; last->next = head; head = last; k--; } return head; }};ListNode* buildList(vector<int>& values) { if (values.empty()) { return nullptr; } ListNode* head = new ListNode(values[0]); ListNode* current = head; for (int i = 1; i < (int)values.size(); i++) { current->next = new ListNode(values[i]); current = current->next; } return head;}void printList(ListNode* head) { ListNode* current = head; while (current != nullptr) { cout << current->data; if (current->next != nullptr) { cout << " -> "; } current = current->next; } cout << endl;}/* Driver code entry point */int main() { vector<int> values = {1, 2, 3, 4, 5}; int k = 2; ListNode* head = buildList(values); Solution solution; ListNode* answer = solution.rotateRight(head, k); printList(answer); return 0;}Complexity Analysis
Time Complexity: O(n + (k % n) × n), The list is traversed once to find its length, and each effective rotation takes O(n) time to find the last node. In the worst case, this becomes O(n²).
Space Complexity: O(1), The list is rotated in-place using only a few pointer variables, so no extra space proportional to the list size is required.
Optimal Approach
Instead of rotating the linked list one step at a time, we first connect the tail node to the head node and temporarily convert the list into a circular linked list. This keeps all nodes connected in order and allows us to choose the correct breaking point directly.
For a right rotation by k, the actual number of rotations is k % length. The new head will be at position length - k from the beginning, and the node just before it becomes the new tail. After locating the new tail, we break the circular link and return the new head.
Algorithm
Return
headdirectly when the list is empty, has only one node, ork = 0, as none of these cases changes the list's order.Traverse the list once to count its length and locate the tail node, since both the effective rotations and the point where the list should be split depend on the length.
Reduce the rotations using
k = k % length, as rotating by the full length restores the original order; ifk = 0, the originalheadis already the required result.Connect the tail node to the
head, temporarily forming a circular linked list, which keeps the entire sequence connected while the new starting point is located.Move
length - k - 1steps from the originalheadto reach the node that should become the new tail, since the node immediately after it will become the new head.Set
newHead = newTail->next, as this node is exactly the position where the rotated list should begin.Break the circular link by setting
newTail->next = NULL, which restores the list as a normal singly linked list.Return
newHeadas the head of the right-rotated linked list.
Dry Run
rotate list optimal
Solution
#include <bits/stdc++.h>using namespace std;struct ListNode { int data; Node* next; ListNode(int value) { data = value; next = nullptr; }};class Solution {public: // Rotates the linked list by k places using a circular connection ListNode* rotateRight(ListNode* head, int k) { // Handle empty list, single node, or zero rotations if (head == nullptr || head->next == nullptr || k == 0) { return head; } int length = 1; ListNode* tail = head; // Locate the tail node while calculating list length while (tail->next != nullptr) { tail = tail->next; length++; } // Skip redundant complete rotation cycles k = k % length; if (k == 0) { return head; } // Link tail to head to form a temporary circle tail->next = head; int stepsToNewTail = length - k - 1; ListNode* newTail = head; // Traverse to locate the node that will serve as the new tail for (int step = 0; step < stepsToNewTail; step++) { newTail = newTail->next; } // Pinpoint the new head node next to the new tail ListNode* newHead = newTail->next; // Break the circular reference to restore linear list structure newTail->next = nullptr; return newHead; }};ListNode* buildList(vector<int>& values) { if (values.empty()) { return nullptr; } ListNode* head = new ListNode(values[0]); ListNode* current = head; for (int i = 1; i < (int)values.size(); i++) { current->next = new ListNode(values[i]); current = current->next; } return head;}void printList(ListNode* head) { ListNode* current = head; while (current != nullptr) { cout << current->data; if (current->next != nullptr) { cout << " -> "; } current = current->next; } cout << endl;}/* Driver code entry point */int main() { vector<int> values = {1, 2, 3, 4, 5}; int k = 2; ListNode* head = buildList(values); Solution solution; ListNode* answer = solution.rotateRight(head, k); printList(answer); return 0;}Complexity Analysis
Time Complexity: O(n), one traversal counts length and another partial traversal locates the break point.
Space Complexity: O(1), only pointer variables are used.
FAQs
Q1. Why do we calculate k % length before rotating the linked list?
Rotating a linked list by its length brings it back to the original order. Therefore, only the remaining rotations after complete cycles need to be performed.
Q2. How is the new head found in the optimal approach?
After reducing k, the new head is the node at position length - k from the beginning of the list. The node just before it becomes the new tail.
Q3. Why is the linked list converted into a circular linked list?
Making the list circular avoids repeatedly moving nodes. After locating the new tail, the circular link is broken to obtain the rotated linked list.
Q4. What happens if k % length is equal to 0?
It means the rotations complete one or more full cycles, so the linked list remains unchanged and the original head is returned.
Be the first to add a comment.