
Problem Statement
In this challenge, you are assigned a singly linked list and an integer k
. Your task is to rotate the list to the right by k
places. This means the last k
elements of the linked list will move to the front, maintaining their order, effectively shifting the list's elements towards the tail, with wrap-around of elements to the list's head. For instance, rotating the list [1,2,3,4,5]
by two positions results in [4,5,1,2,3]
.
Examples
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 <= 100
0 <= k <= 2 * 109
Approach and Intuition
When faced with a linked list rotation problem, the intuitive approach is to reconnect the tail of the list to the head and then locate the new head and tail based on the value of k
. Here’s how to systematically achieve this:
- Address the special cases, especially when the linked list is empty or
k
is zero, which means no rotation is needed. - Normalize
k
as rotating a list of lengthn
byn
,2n
, or any multiple ofn
results back in the same list. This is done usingk = k % n
. - Identify the new tail of the list, which will be at position
(n - k - 1)
ifn
is the length of the list. - Make the node at position
(n - k)
the new head and the node at position(n - k - 1)
should point tonull
(breaking the loop created by connecting the old tail to the head).
The challenge is simplified by understanding two key concepts:
- A full rotation of the list by its length
n
results in the same list. This observation allows us to reduce computational steps dramatically whenk
is large (e.g., in the order of billions). - The essence of rotation logic lies in reconnecting the tail to the head and correctly determining the new head based on the
k
rotations reduced modulo. This ensures our solution works efficiently within the constraint limits.
Given the constraints like a limit of 500 nodes, this approach ensures optimal computation without running into performance bottlenecks or unnecessary complexity.
Solutions
- C++
- Java
- C
- JavaScript
- Python
class Solution {
public:
ListNode* rotateLinkedList(ListNode* head, int k) {
if (!head || !(head->next)) return head;
ListNode* lastNode = head;
int length;
for (length = 1; lastNode->next; length++) lastNode = lastNode->next;
lastNode->next = head;
ListNode* newEnd = head;
for (int i = 0; i < length - k % length - 1; i++) newEnd = newEnd->next;
ListNode* newHead = newEnd->next;
newEnd->next = NULL;
return newHead;
}
};
This C++ solution implements a function to rotate a singly linked list by k
places. Here's how the code accomplishes this:
- The function
rotateLinkedList
starts by checking if the list is empty or only contains one node, returning the head if true, as no rotation is needed. - It proceeds to determine the length of the list by iterating through the list until it reaches the last node, storing the length in the variable
length
. - The last node's next pointer is set to point back to the head, forming a circular linked list temporarily.
- To find the correct new end of the rotated list, the code calculates the effective rotation needed (with
k % length
) since rotating a list by its length results in the same list. - It then iterates through the list to the new end node (
length - k % length - 1
times). - The new head of the list is the node right after the new end.
- To finalize the list rotation, the next pointer of the new end node is set to NULL, breaking the circular structure and establishing the new end.
- The function returns the new head, effectively rotating the list to the right by
k
places.
Key Points:
- The rotation is efficiently handled by first forming a circular list and then fixing the correct start and end points.
- Calculating
k % length
avoids unnecessary rotations equivalent to the entire list length or more. - The method ensures every node is visited only a limited number of times, resulting in a linear time complexity relative to the number of nodes.
class Solution {
public ListNode rotateLinkedList(ListNode startNode, int rotations) {
if (startNode == null) return null;
if (startNode.next == null) return startNode;
ListNode tailNode = startNode;
int listLength;
for (listLength = 1; tailNode.next != null; listLength++) tailNode = tailNode.next;
tailNode.next = startNode;
ListNode newTail = startNode;
for (int i = 0; i < listLength - (rotations % listLength) - 1; i++) newTail = newTail.next;
ListNode newHead = newTail.next;
newTail.next = null;
return newHead;
}
}
The provided Java solution details a method for rotating a linked list to the right by a specified number of positions. The method, rotateLinkedList
, takes two parameters: the head of the linked list (startNode
) and the number of rotations (rotations
). The approach involves several steps:
- First, handle edge cases where the linked list is empty or consists of a single node. In these scenarios, return
null
or the node itself, respectively. - Establish the length of the list and create a circular linked list by linking the last node (
tailNode
) back to thestartNode
. - Calculate the effective number of rotations needed by taking the modulus of the rotations with the list length. This accounts for scenarios where the number of rotations exceeds the length of the list.
- Identify the new tail of the linked list, which is positioned at
listLength - (rotations % listLength) - 1
from the start, by traversing the list. The node next to this new tail becomes the new head of the rotated list. - Finally, break the circular link by setting the
next
property of the new tail node tonull
.
The method returns the new head of the rotated list as the output. Through this approach, the list is efficiently rotated in place without needing additional lists or storage, optimizing both time and space complexity. This solution leverages the circular linked list concept to simplify rotation and achieve the desired configuration.
struct ListNode* rotateLinkedList(struct ListNode* head, int k) {
if (head == NULL || head->next == NULL) return head;
struct ListNode* lastElement = head;
int len;
for (len = 1; lastElement->next != NULL; len++) lastElement = lastElement->next;
lastElement->next = head;
struct ListNode* new_tail = head;
for (int i = 0; i < len - k % len - 1; i++) new_tail = new_tail->next;
struct ListNode* new_head = new_tail->next;
new_tail->next = NULL;
return new_head;
}
The provided C function rotateLinkedList
rotates a singly linked list right by k
places. Here's how it achieves this rotation:
- First, check if the list is empty (i.e.,
head
isNULL
) or has only one element (i.e.,head->next
isNULL
). If either condition is true, return thehead
since no rotation is needed. - Initialize a pointer
lastElement
to traverse the list and determine its length (len
). Also, setlastElement->next
to point tohead
to temporarily create a circular linked list. - Calculate the new tail of the list which is
len - k % len - 1
steps from the head. Use a loop to move the pointernew_tail
to this position. - Define
new_head
as the node immediately afternew_tail
(i.e.,new_tail->next
). This will be the new head of the rotated list. - Set
new_tail->next
toNULL
to break the circular linkage, thus formally defining the end of the linear linked list. - Return
new_head
, the new start of the rotated list.
This function efficiently handles lists of any size and correctly adjusts for rotations larger than the list's length using k % len
. The use of a circular linked list strategy simplifies the rotation process without needing additional data structures.
var rotateLinkedList = function(node, rotations) {
if (node == null) return null;
if (node.next == null) return node;
let lastNode = node;
let length;
for (length = 1; lastNode.next != null; length++)
lastNode = lastNode.next;
lastNode.next = node;
let newLast = node;
for (let i = 0; i < length - rotations % length - 1; i++)
newLast = newLast.next;
let newHead = newLast.next;
newLast.next = null;
return newHead;
};
The provided solution tackles the task of rotating a singly linked list to the right by a given number of positions. It is written in JavaScript as a function rotateLinkedList
that accepts two parameters: node
, which is the head of the linked list, and rotations
, the number of positions by which the list should be rotated.
Behavior Analysis:
- The solution first checks if the list is empty (
node == null
) or contains a single element (node.next == null
), in which cases it returns the list as is since no rotation is needed or possible. - The function calculates the linked list's length by traversing from the head node to the last node.
- It connects the last node of the list to the head, forming a circular linked list temporarily.
- Using the formula
(length - rotations % length - 1)
, the new end of the rotated list is found. This calculation ensures handling rotations exceeding the length of the list. - It sets
newLast.next
tonull
to break the circular form and establish the new end of the list. - Finally,
newHead
, the starting node of the rotated list, is returned.
Further Explanation:
- By connecting the head to the last node, the list manipulation becomes easier as it allows the rotation to be handled without explicitly handling node relinking for each rotation.
- The modulo operation with the list's length (
rotations % length
) ensures that the number of rotations do not exceed the list's length, preventing unnecessary processing. - This code guarantees an O(n) time complexity since it involves a complete traversal of the list at least twice, making it efficient for reasonable list sizes and rotation values.
class Solution:
def rotateList(self, head: Optional[ListNode], k: int) -> Optional[ListNode]:
if not head or not head.next:
return head
# Create a closed loop
last_node = head
length = 1
while last_node.next:
last_node = last_node.next
length += 1
last_node.next = head
# Find the point to break the loop
steps_to_new_head = length - k % length
new_end = head
for _ in range(steps_to_new_head - 1):
new_end = new_end.next
starting_head = new_end.next
# Break the loop
new_end.next = None
return starting_head
The provided Python solution is designed to rotate a linked list by k
positions to the right. The process involves several key operations:
Initially, the function checks if the
head
isNone
or if the list contains only one node. In either case, it returns thehead
as no rotation is needed.The algorithm then creates a closed loop from the list. This is achieved by traversing to the last node of the list, counting the nodes along the way to ascertain the length, and then connecting the last node back to the head.
Once the list has been converted into a circular linked list, the rotation is handled by computing the effective number of rotations needed (
k % length
). This calculation is necessary because rotating a list of lengthL
byL
times results in the same list, hence rotations beyond the length of the list are redundant.Determining the new head involves moving to the
length - k % length
node in the list. This traversal is performed starting from the current head.After identifying the new end of the rotated list (
new_end
), the node next tonew_end
is set as the newhead
, and the circular linkage is broken by settingnew_end.next
toNone
.Finally, the function returns the new head of the rotated list, effectively completing the rotation.
This solution makes use of a clever technique to minimize the list traversals and is efficient in terms of time and space with regard to handling list rotations.
No comments yet.