Left Rotate Array by One
Java source ↗ Edit this article ↗
Jump to code:
Problem
You are given an array of integers nums. Rotate it left by one position: every element moves one index towards the front, and the element that was at index 0 wraps around to the last index. Do it in place.
Constraints: 0 ≤ n ≤ 10^5, values fit in a 32-bit signed integer.
Example 1
nums = [1, 2, 3, 4, 5]
after = [2, 3, 4, 5, 1] // 1 leaves the front and reappears at the back
Example 2
nums = [1, 2]
after = [2, 1] // with two elements a rotation is just a swap
Example 3
nums = [7]
after = [7] // a single element rotates onto itself
The problem is tiny, but it introduces the idea that defines in-place array manipulation: when you move elements around inside one buffer, the order of the moves decides whether you overwrite something before you have read it. Getting this right here is the foundation for rotating by k, for deleting from an array, and for every two-pointer compaction later on.
Approach 1: Brute force, build the answer in a second array
Intuition. If overwriting is the danger, avoid it entirely: write the rotated arrangement into a fresh array, where no slot is ever read after being written, then copy that array back over the original. The index mapping is rotated[i - 1] = nums[i] for i ≥ 1, and rotated[n - 1] = nums[0].
Algorithm.
- If
n == 0, there is nothing to do. - Allocate
rotatedof sizen. - For
ifrom1ton - 1, setrotated[i - 1] = nums[i]. - Set
rotated[n - 1] = nums[0]. - Copy
rotatedback intonums.
static void bruteForce(int[] nums) {
int n = nums.length;
if (n == 0) return;
int[] rotated = new int[n];
for (int i = 1; i < n; i++) rotated[i - 1] = nums[i];
rotated[n - 1] = nums[0];
for (int i = 0; i < n; i++) nums[i] = rotated[i];
}
Complexity. Time O(n): two linear passes. Space O(n) for the temporary array, which is the part worth eliminating. Rotating a 100 MB array should not need another 100 MB.
Approach 2: Optimal, save the first element and shift
Intuition. Only one element, nums[0], is going to be overwritten before it reaches its destination. Save it in a variable. Then shift the remaining elements left one at a time, going from left to right: when we write nums[i - 1] = nums[i], the slot nums[i - 1] has already been read (it was moved one step earlier), so nothing is lost. Finally place the saved value at the end.
Had we shifted from right to left, nums[n - 2] = nums[n - 1] would destroy the old nums[n - 2] before it was moved, and the array would fill up with copies of the last element. Direction is the entire algorithm.
Algorithm.
- If
n == 0, return. first = nums[0].- For
ifrom1ton - 1:nums[i - 1] = nums[i]. nums[n - 1] = first.
static void optimal(int[] nums) {
int n = nums.length;
if (n == 0) return;
int first = nums[0];
for (int i = 1; i < n; i++) nums[i - 1] = nums[i]; // left to right, so nothing is overwritten before it is read
nums[n - 1] = first;
}
Dry run on nums = [1, 2, 3, 4, 5], with first = 1:
| i | write | array |
|---|---|---|
| 1 | nums[0] = nums[1] | [2, 2, 3, 4, 5] |
| 2 | nums[1] = nums[2] | [2, 3, 3, 4, 5] |
| 3 | nums[2] = nums[3] | [2, 3, 4, 4, 5] |
| 4 | nums[3] = nums[4] | [2, 3, 4, 5, 5] |
| end | nums[4] = first | [2, 3, 4, 5, 1] |
Notice that after each step the array temporarily holds a duplicate; that is normal, it is the slot about to be overwritten next.
Complexity. Time O(n): n - 1 moves plus one write. Space O(1): one saved value.
Approach 3: The same shift with System.arraycopy
Intuition. Shifting a contiguous block is so common that the JDK provides a native routine for it. System.arraycopy(src, srcPos, dest, destPos, length) copies length elements, and the specification guarantees correct behaviour even when src and dest are the same array and the ranges overlap: it behaves as if the source range were first copied to a temporary buffer. So the whole shift collapses to one call, and we keep only the wrap-around step by hand.
Algorithm.
- If
n == 0, return. first = nums[0].System.arraycopy(nums, 1, nums, 0, n - 1).nums[n - 1] = first.
static void optimalArraycopy(int[] nums) {
int n = nums.length;
if (n == 0) return;
int first = nums[0];
System.arraycopy(nums, 1, nums, 0, n - 1);
nums[n - 1] = first;
}
Complexity. Time O(n), space O(1); the call is a tight native memory move and is noticeably faster than the hand-written loop on large arrays.
The explicit loop in Approach 2 is what you should be able to write on a whiteboard; arraycopy is what you should write in production. Knowing that the overlapping case is safe is the useful fact here, because ArrayList.remove(0) and many ring-buffer implementations rely on exactly that.
Edge cases and pitfalls
- Empty array. All three methods return immediately. Without the guard,
nums[0]throwsArrayIndexOutOfBoundsExceptionandSystem.arraycopy(..., n - 1)would be asked to copy-1elements, which also throws. - Single element.
first = nums[0], the loop does nothing,nums[0] = first. The array is unchanged, as it should be. - Shifting in the wrong direction. Writing
nums[i] = nums[i - 1]from the right would be a right rotation and needs the last element saved instead. Left rotation reads ahead (nums[i]) and writes behind (nums[i - 1]); right rotation does the opposite and must iterate from the end. - Forgetting to save the first element. Then
nums[0]is overwritten in the very first iteration and the value is gone for good. - Rotating
ntimes. Rotating by onentimes returns the array to its original order; the tests use this as a sanity check ([4, 8, 15, 16, 23, 42]after six rotations). - Duplicates.
[3, 3, 3]is unchanged by any rotation; the code neither knows nor cares. - Extreme values. No arithmetic is done on the values, only moves, so
Integer.MIN_VALUEandInteger.MAX_VALUEare safe.
Related problems
- Left Rotate Array by K Places generalises this to
kpositions; repeating this methodktimes is its brute force, and the reversal trick is its optimal solution. - Check if the Array is Sorted II asks whether an array is a rotation of a sorted one.
- Move Zeros to End and Remove duplicates from Sorted array rely on the same “write behind the read position” safety argument.
- Rotate String asks the rotation question about characters instead of integers.