Rotate Array by d asks you to shift every element of an array by d positions. The naive moves are easy but wasteful; the elegant answer is a trick worth memorizing — three in-place reversals that rearrange the whole array with no extra memory.
Problem. Given an array arr and an integer d, rotate the array left by d positions: the
first d elements move to the back, in order. Do it in place (no second array).
Example: arr = [1, 2, 3, 4, 5, 6, 7], d = 2 → answer [3, 4, 5, 6, 7, 1, 2] (the leading 1, 2
slid to the end).
The slow way first
The obvious idea: rotate one position at a time. Save the first element, shift everything left by one, drop the saved element at the end — then repeat d times. Each pass is O(n) and we do d passes, so it is O(n·d) time. For a large array and a large d that is far too slow.
A second naive idea uses a temporary array: copy each element to its rotated index. That is O(n) time but costs O(n) extra space. Can we get O(n) time and O(1) space? Yes — by reversing.
The idea: three reversals flip it into place
Here is the trick. To rotate left by d:
- Reverse the first
delements — the slice[0 .. d-1]. - Reverse the remaining
n - delements — the slice[d .. n-1]. - Reverse the whole array — the slice
[0 .. n-1].
That is it. Three reversals, each a simple two-pointer swap loop, and the array lands rotated.
Why does it work? Reversing the two halves separately puts the elements of each half in backward order. The final full reverse flips everything back to forward order and swaps the two blocks — which is exactly a rotation.
Walk through it
Step through the animation on [1,2,3,4,5,6,7] with d = 2. In each phase the l and r pointers mark the slice being reversed; they start at the two ends and swap inward until they meet. Phase 1 flips 1,2 to 2,1. Phase 2 flips the back five to 7,6,5,4,3. Phase 3 reverses the entire array, and the cells settle into [3,4,5,6,7,1,2].
Pseudocode
reverse(l, r): # flip a slice in place, two pointers
while l < r:
swap arr[l] and arr[r]
l = l + 1
r = r - 1
rotate(arr, d):
n = length of arr
d = d mod n # rotating by n is a no-op
reverse(0, d - 1) # flip the first d
reverse(d, n - 1) # flip the rest
reverse(0, n - 1) # flip the whole array
return arrThe Python solution
def rotate(arr, d):
def reverse(l, r):
while l < r:
arr[l], arr[r] = arr[r], arr[l]
l += 1
r -= 1
n = len(arr)
d %= n
reverse(0, d - 1)
reverse(d, n - 1)
reverse(0, n - 1)
return arrreverse(l, r)is a tiny helper: while the two pointers have not crossed, swap the ends and step them inward. This is the classic two-pointer reversal.d %= nguards against adlarger than the array (rotating bynlands back where you started, so onlyd mod nmatters).- The three
reversecalls are the whole algorithm: firstd, then the rest, then everything. - Every swap is in place, so we never allocate a second array — that is the O(1) space win.
Complexity
| Case | Time | Notes |
|---|---|---|
| Rotate one-by-one | O(n·d) (moderate) | d passes, each shifts n elements |
| Extra-array copy | O(n) (moderate) | fast, but O(n) extra space |
| Reversal (this solution) | O(n) (moderate) | each element is swapped a constant number of times |
O(1) (fast)Each of the three reversals touches each element at most once, so the total work is linear — O(n) time. No extra array means O(1) space. That combination is what makes the reversal trick the textbook answer.
When this pattern shows up
Reversing sub-ranges is a surprisingly general tool. Rotation, reversing words in a sentence, and many
array-rearrangement puzzles all reduce to a few well-placed reverse(l, r) calls. When a problem wants
blocks of an array swapped without extra memory, think reversals.
Mind the rotation direction and the d %= n guard. This code rotates left by d. To rotate
right by d instead, rotate left by n - d (or reorder the reversals). And without d %= n, a d
bigger than n sends a pointer out of bounds.
Practice
After reverse(0, d-1) and reverse(d, n-1) on [1,2,3,4,5,6,7] with d = 2, the array is [2,1,7,6,5,4,3]. What does the final reverse(0, n-1) produce?
1. What is the space complexity of the three-reversal method?
2. Why do we compute d %= n before rotating?
3. What is the correct order of the three reversals to rotate left by d?
4. Why is the reversal method faster than rotating one position at a time?