Problem overview
The method rotate receives an int[] called nums and moves every element one position to the right. The last element wraps around to the front. The method returns nothing: it must change the array it was given, without building a second array.
For nums = [1, 2, 3, 4, 5] the array becomes [5, 1, 2, 3, 4]. For [4, -2, 13, 1] it becomes [1, 4, -2, 13]. The statement asks for O(n) time and O(1) auxiliary space, meaning a fixed number of extra variables, whatever the array's size.
Approach: save the last element, shift, then place it
Every element except the last moves one slot right, to the place its right neighbour occupies. The last element has no slot to its right, so it goes to index 0. The difficulty is the order of the writes: moving an element onto its neighbour's slot overwrites the neighbour.
Two decisions solve it:
- Save the last element in a variable before anything is overwritten, since its slot is the first one to be reused.
- Do the shifting from right to left. Copying
nums[i - 1]intonums[i]overwritesnums[i], and by then that value has already been copied one slot further right, or was saved at the start. Nothing is lost.
Tracing [1, 2, 3, 4, 5]: save last = 5. Then the array goes through [1, 2, 3, 4, 4], [1, 2, 3, 3, 4], [1, 2, 2, 3, 4] and [1, 1, 2, 3, 4]. Finally index 0 gets the saved 5, giving [5, 1, 2, 3, 4].
Step by step
- Record the length in
nand save the last element inlast, usingnums[n - 1]. This is the only value that would otherwise be lost. - Loop backwards with
ifromn - 1down to 1. The conditioni > 0stops the loop before index 0, because index 0 has no left neighbour to copy from. - Copy each neighbour to the right. Assign
nums[i] = nums[i - 1]. The right-to-left order guarantees thatnums[i - 1]still holds its original value when it is read. - Place the saved value. After the loop, set
nums[0] = last. The old first element was already copied to index 1 in the final iteration, so index 0 is free to overwrite.
The solution in Java
class Solution {
public void rotate(int[] nums) {
int n = nums.length;
int last = nums[n - 1];
for (int i = n - 1; i > 0; i--) {
nums[i] = nums[i - 1];
}
nums[0] = last;
}
}
The Java details worth a closer look:
- Arrays are passed by reference. The method gets a reference to the caller's array, so writes to
nums[i]change the caller's data. That is why avoidmethod can deliver its result. Assigning a new array to the parameter, such asnums = new int[n], would change only the local variable and the caller would see no rotation. - Primitive values are copied.
int last = nums[n - 1]copies the number into its own variable. Later writes to the array do not affect it. lengthhas no parentheses. For arrays it is a field,nums.length, whileStringand collections use methods such aslength()andsize().- Indexes are checked. Java throws
ArrayIndexOutOfBoundsExceptionfor an index outside0tolength - 1rather than touching other memory.
Complexity
Time: O(n). The loop runs n - 1 times and does one assignment each time.
Space: O(1). The code uses n, last and i, three integers, whatever the length of the array.
Edge cases and common mistakes
- One element. For
[7]the loop body never runs, andnums[0] = lastwrites back the same value. The array is unchanged, which is correct. - Two elements.
[1, 2]becomes[2, 1]. - An empty array.
nums[n - 1]isnums[-1], which throwsArrayIndexOutOfBoundsException. The lesson's tests don't use an empty array, but a version meant for general use would begin withif (n == 0) return;. - Shifting left to right. A loop that runs upwards and copies
nums[i] = nums[i - 1]smears the first value across the whole array:[1, 2, 3, 4, 5]turns into[1, 1, 1, 1, 1]. - Forgetting to save the last element. Without
last, the value 5 is overwritten by the first copy and there is nothing to put at index 0. - Looping down to
i >= 0. The final iteration would readnums[-1]and throw. - Allocating a new array. A copy gives the right values, but it uses
O(n)extra space, which the statement forbids.
Testing
[1, 2, 3, 4, 5]becomes[5, 1, 2, 3, 4].[4, -2, 13, 1]becomes[1, 4, -2, 13].[7]stays[7].[1, 2]becomes[2, 1].