Array Rotation (Left and Right)
Question
Given an integer array and a non-negative integer , rotate the array:
- To the Right: elements from the back move to the front.
- To the Left: elements from the front move to the back.
The operation must be performed in-place with extra space.
Solution
Pattern
The Triple Reversal Algorithm A mathematical property where an array can be divided into two parts and . By reversing , then , then the entire array , we achieve a cyclic shift.
How to Identify
- Requirement for in-place modification of a sequence.
- Cyclic shifts or rotations where elements "wrap around."
- Constraints demanding space and time.
Description
Step-by-step explanation:
- Step 1: Normalize . Since rotating times is a null operation, set .
- Step 2: Partition the Array. - For Right Rotation: Divide at index .
- For Left Rotation: Divide at index .
- Step 3: Reverse the Parts.
- Reverse the first part.
- Reverse the second part.
- Step 4: Global Reverse.
- Reverse the entire array from index to .
The Intuition
Think of the array as two separate blocks: and . If you want to move to the end (Left Rotation), the goal is to transform into .
- Reverse
- Reverse
- Reverse the whole thing
Complexity
| Label | Worst | Average |
|---|---|---|
| Time Complexity | ||
| Space Complexity |
Time Complexity
. Each element is swapped a maximum of two times across the three reversal steps ( operations), which simplifies to linear time.
Space Complexity
. Only a single temporary variable is used for swapping, regardless of input size.
Code
class Solution {
/**
* Rotates array to the right by k steps.
* Logic: Reverse (0 to n-k-1), then (n-k to n-1), then (0 to n-1)
*/
public void rotateRight(int[] nums, int k) {
if (nums == null || nums.length < 2) return;
int n = nums.length;
k %= n;
if (k == 0) return;
reverse(nums, 0, n - k - 1);
reverse(nums, n - k, n - 1);
reverse(nums, 0, n - 1);
}
/**
* Rotates array to the left by k steps.
* Logic: Reverse (0 to k-1), then (k to n-1), then (0 to n-1)
*/
public void rotateLeft(int[] nums, int k) {
if (nums == null || nums.length < 2) return;
int n = nums.length;
k %= n;
if (k == 0) return;
reverse(nums, 0, k - 1);
reverse(nums, k, n - 1);
reverse(nums, 0, n - 1);
}
private void reverse(int[] nums, int start, int end) {
while (start < end) {
int temp = nums[start];
nums[start] = nums[end];
nums[end] = temp;
start++;
end--;
}
}
}Caveats
- or : Always perform the modulus and check if is 0 to avoid unnecessary processing.
- Empty Arrays: Defensive coding for
nullorlength == 0is essential for production-grade code. - Integer Overflow: If is provided as a very large long, casting and modulus must be done carefully.
Concepts to Think About
-
Cyclic Buffers: In many real-world applications (like OS kernels), instead of shifting data, we move the "start" pointer in a virtual circular array.
-
Cache Locality: The reversal algorithm is faster than the "Juggling" algorithm because it accesses memory in a linear, predictable sequence, which modern CPUs optimize via prefetching.
-
GCD Juggling: Understanding how the Greatest Common Divisor determines the number of cycles in a permutation.
-
Left vs. Right Rotation: To perform a Right Rotation by k, the logic is slightly different. You would reverse the last k elements, then the first n−k, then the whole. Can you see how the "split point" moves?
-
The Juggling Algorithm: There is another O(1) space approach using the Greatest Common Divisor (GCD) of n and k. It moves elements in "cycles." While harder to code, it performs fewer total assignments than the Reversal method.
-
Block Swap Algorithm: This is another O(n) time approach that is very efficient for large k. It works by swapping blocks of size k recursively.
-
Why Modulo? If n=5 and k=7, rotating 7 times is the same as rotating 2 times (7(mod5)). Always include this to show you understand cyclic properties.
Logical Follow-up
Question: Can you solve this with space without using the reversal trick? Solution: Use the Juggling Algorithm. Calculate . There are cycles to process. For each cycle, move elements to their target positions one by one.
Question: How would you rotate a linked list by ? Solution: Find the node, make the list circular by connecting the tail to the head, set the new head to the node, and break the circular connection.