Problem
Given an integer array and a non-negative integer k, shift every element k positions to the right, wrapping elements that fall off the end back to the beginning. The modification must happen in-place.
Example:
- Input:
nums = [1, 2, 3, 4, 5, 6, 7],k = 3 - Output:
[5, 6, 7, 1, 2, 3, 4] - Explanation: The last 3 elements (5, 6, 7) wrap to the front; the first 4 elements shift right by 3 positions.
Counter-example: k = 7 on the same array gives back [1, 2, 3, 4, 5, 6, 7] โ identical to the input โ because rotating by the full length completes a cycle. Always reduce k modulo n first.
Intuition
Rotating right by k is exactly the same as moving the last k elements to the front. The three-reversal trick exploits a clean algebraic fact: reversing the whole array places those last k elements at the front but in reverse order, and then reversing each half independently restores their original relative order โ yielding the correct rotation in O(n) time with no extra memory.
Approach 1 โ Brute Force
Perform k individual one-step rotations, each time saving the last element and shifting everything else one position to the right.
Steps:
- Reduce k with
k = k % nto skip full-cycle rotations. - Repeat k times: save
nums[n-1], shift every element right by one scanning right to left, place the saved value atnums[0].
1def rotate(nums: list[int], k: int) -> None:
2 n = len(nums)
3 k = k % n
4 for _ in range(k):
5 last = nums[-1] # element that wraps around to position 0
6 for i in range(n - 1, 0, -1):
7 nums[i] = nums[i - 1]
8 nums[0] = last- Time: O(n ร k) โ each of k rotations shifts all n elements one position
- Space: O(1) โ one temporary variable regardless of input size
Approach 2 โ Extra Array
Place each element directly at its final position in a new array using the formula (i + k) % n, then copy back into nums.
Steps:
- Compute
k = k % n. - Allocate a result array of the same length.
- Write
nums[i]toresult[(i + k) % n]for every index. - Copy result back into
numsin-place.
1def rotate(nums: list[int], k: int) -> None:
2 n = len(nums)
3 k = k % n
4 rotated = [0] * n
5 for i in range(n):
6 rotated[(i + k) % n] = nums[i] # jump each element k spots ahead, wrapping around
7 nums[:] = rotated # slice assignment mutates in-place; nums = rotated would not- Time: O(n) โ one pass to compute positions, one pass to copy back
- Space: O(n) โ auxiliary array of length n
Approach 3 โ Three Reversals
Reverse the entire array, then reverse the first k elements, then reverse the remaining n-k elements. After the global flip the last-k block is at the front but internally reversed; each sub-reversal restores its segment's original left-to-right order.
Steps:
- Compute
k = k % n. - Reverse the entire array (indices 0 to n-1).
- Reverse the first k elements (indices 0 to k-1).
- Reverse the remaining elements (indices k to n-1).
1def rotate(nums: list[int], k: int) -> None:
2 n = len(nums)
3 k = k % n
4
5 def reverse(left: int, right: int) -> None:
6 while left < right:
7 nums[left], nums[right] = nums[right], nums[left]
8 left, right = left + 1, right - 1
9
10 reverse(0, n - 1) # flip everything so last k land at the front, reversed
11 reverse(0, k - 1) # un-flip first k back to their original left-to-right order
12 reverse(k, n - 1) # un-flip trailing n-k back to their original left-to-right order- Time: O(n) โ three reversal passes that together touch every element exactly twice
- Space: O(1) โ all swaps are in-place with no auxiliary storage
Complexity Summary
| Approach | Time | Space | When to use |
|---|---|---|---|
| Brute Force | O(n ร k) | O(1) | Only for tiny arrays where k is very small |
| Extra Array | O(n) | O(n) | When extra memory is available and you want simpler code |
| Three Reversals | O(n) | O(1) | Default โ interviews almost always ask for O(n) time and O(1) space |
Common Mistakes
- Forgetting
k = k % nโ when k equals n, rotating by the full length returns the original array unchanged; without the modulo, the brute-force runs n useless sweeps and the three-reversal approach passes k=n to its first sub-reversal, which silently produces the wrong result by treating the "second half" as empty. - Reversing the two halves before the full array โ the three-reversal technique requires the global flip first; reversing the halves before the whole array produces a different permutation that is not a rotation of the original input.
- Reassigning
numsinstead of mutating it in Python โ writingnums = rotatedrebinds the local variable but leaves the caller's list untouched;nums[:] = rotatedperforms an in-place copy that actually modifies the original object. - Overwriting source values in Approach 2 without a separate array โ applying
nums[(i + k) % n] = nums[i]directly onnumscorrupts values at destination indices before they've been read, because rotation offsets cause reads and writes to overlap whenever k is not a multiple of n. - Confusing k and n-k as the split point โ after the global flip, the block that needs to land at the front spans exactly k elements (indices 0 to k-1); using n-k as the boundary gives the correct structure but in the wrong half, rotating the array in the opposite direction.
Related Problems
rotate-imageโ applies the same reversal-based rotation idea in two dimensions: transpose then reflect to rotate a matrix 90 degrees in-placereverse-stringโ the two-pointer reversal primitive that Approach 3 is built onnext-permutationโ in-place rearrangement whose final step reverses a suffix, the same operation as Approach 3's third reversalproduct-of-array-except-selfโ O(n) in-place transformation using a left-to-right pass followed by a right-to-left pass, mirroring the multi-sweep structure of Approach 3