Array rotation
Shift every item in an array by k places, wrapping around the end, in place with three reversals.
O(n)Space O(1)5 practice problemsStep-through pictureThe idea
Rotating an array to the right by k moves every item k places to the right, and the items that fall off the end come back at the start. Rotating [1, 2, 3, 4, 5] right by 2 gives [4, 5, 1, 2, 3].
The easy way builds a new array: the item at index i goes to index (i + k) % n. That uses O(n) extra memory. The reversal trick does it in place: reverse the whole array, then reverse the first k items, then reverse the rest.
Why it works: reversing the whole array brings the last k items to the front, but backwards, and the other items to the back, also backwards. Reversing each part again puts both parts back in their original order.
An everyday example
Moving train cars from the back to the front
A train needs its last 2 cars moved to the front. Turn the whole train around on a loop track: now the last 2 cars lead, but in reverse order, and so do the rest. Turn the first 2 cars around on their own, and they're in the right order. Turn the remaining cars around too. The whole train now reads in the right order, with the last 2 cars at the front, and no extra track was needed.
| In the example | In the code |
|---|---|
| The train | nums |
| How many cars move to the front | k |
| Turning the whole train around | reverse(nums, 0, n - 1) |
| Turning the front cars around | reverse(nums, 0, k - 1) |
| Turning the remaining cars around | reverse(nums, k, n - 1) |
From the slow way to array rotation
- The obvious way to rotate right by
kis to move the last item to the front,ktimes, withnums.unshift(nums.pop()). Eachunshiftshifts every item over by one, so that costsO(n × k). Copying each item into a new array at(i + k) % nisO(n)time but needs a second array. - Look at the result as two blocks. Call the first
n - kitemsAand the lastkitemsB. Rotating right bykturnsA BintoB A. So the real question is how to swap two blocks of different sizes inside one array. - Reversing part of an array in place is easy: swap its two ends and step inward. And reversing the whole array does swap the blocks:
Bends up in front andAat the back. But each block now reads backwards. - Reversing each block a second time fixes the order inside it. Reverse everything, reverse the first
k, then reverse the rest: three reversals and no extra array. That loop is array rotation.
How it works
- Let
n = nums.length. If it's 0, there's nothing to do. - Reduce
kwithk = k % n: rotating bynchanges nothing. - Reverse the whole array.
- Reverse the first
kitems (indexes0tok - 1). - Reverse the remaining items (indexes
kton - 1). - The array is now rotated right by
k.
Watch it run
This picture runs the code below on a real input. Press Step to move one step at a time, or Play to watch. The highlighted line is the one that just ran. Change the input to see other cases.
See every step at onceThe same run, laid out side by side
The code
Point at a note to light up the lines it explains.
function rotateRight(nums, k) {const n = nums.length;if (n === 0) return nums;k = k % n;reverse(nums, 0, n - 1);reverse(nums, 0, k - 1);reverse(nums, k, n - 1);return nums;}function reverse(nums, start, end) {while (start < end) {[nums[start], nums[end]] = [nums[end], nums[start]];start++;end--;}}
How fast it is
| Time | O(n) |
|---|---|
| Extra memory | O(1) |
The three reversals swap each item at most twice in total. Only start, end, and k are stored.
- Best case
O(n)Even
k = 0reverses the whole array twice: 6 swaps for 6 items, ending where it began. Return early whenkis 0 to skip them. - Average case
O(n)About
nswaps for anyk, split across the three reversals. - Worst case
O(n)No
kcosts more than aboutnswaps, and a hugekis reduced first withk % n.
Common mistakes
- Forgetting
k = k % n. Withkbigger thann, the reversals use indexes outside the array. - Reversing the first
n - kitems instead of the firstk, which rotates left instead of right. - Rotating by moving the last item to the front
ktimes withunshift(pop()). Eachunshiftshifts every item:O(n * k). - Returning a new array when the problem says to change the input in place.
When to use it
Look for these clues in a problem:
- The problem says rotate, shift, cycle, or wrap around.
- Items that go past the end come back at the start.
- You must change the array in place with
O(1)extra space. kcan be larger than the array's length.
Check yourself
Answer each one in your head first, then open it.
How many swaps did the trace make, and why can a 6-item array never need more than 6?
6. The three reversals cover 6, 2, and 4 items, which take 3, 1, and 2 swaps. Half of each part adds up to at most n.
Where does the item at index i end up after rotating right by k?
At index (i + k) % n. In the trace, 10 starts at index 0 and ends at index 2.
What happens if you reverse the first n - k items instead of the first k?
The blocks are split in the wrong place, so the array is rotated left by k instead of right.
Why must k % n happen before the reversals?
With k = 8 and n = 6, reverse(nums, 0, 7) would swap with indexes past the end and write undefined into the array.
Practice problems
Stuck on one? Tuto is in the playground too, and gives you hints, never the answer.
0 of 5 solved. Solve one to earn the bronze medal, half for silver, and all of them for gold.
Start practicingGo further
You don't need these to start practicing. Open one when you want more.
Why it works
The reasoning that makes it always right
Reversing a list made of two parts reverses the order of the parts and also reverses each part: the reverse of A B is reverse(B) reverse(A). That's because the item at position p moves to position n - 1 - p, so the last k items land in the first k slots, in backwards order.
After the first reversal, the first k slots hold exactly the items of B, backwards, and the rest hold A, backwards. Reversing each part separately undoes those inner reversals, leaving B A, which is the rotation. In index terms, the item that started at index i ends at (i + k) % n.
Each reverse call ends because start and end move toward each other by one per swap. A call over m items makes Math.floor(m / 2) swaps, so the three calls together make at most n swaps.
Going deeper
4 more ideas
Why three reversals rotate
Write the array as two parts, A (the first n - k items) and B (the last k). Rotating right by k should give B A. Reversing everything gives reverse(B) reverse(A): the parts have swapped places but each reads backwards. Reversing each part separately fixes them, giving B A.
Rotating left and large k
Rotating left by k is the same as rotating right by n - k. Or swap the order: reverse the first k, reverse the rest, then reverse everything. Always reduce with k % n first, since k can be in the billions, and rotating by n does nothing.
Index math instead of moving items
Often you don't need to move anything. After rotating right by k, the item at index i is the original nums[(i - k + n) % n]. Carousels and circular buffers use this: they keep a start offset and compute positions with %, so rotating is just changing one number.
Cost
Each item is swapped at most twice across the three reversals, so the time is O(n), and only a few index variables are used: O(1) space.
Work it by hand
Every step in a table, with why
Rotate 6 numbers right by k = 8, which is bigger than the length.
nums = [10, 20, 30, 40, 50, 60], k = 8
| Step | Step | start | end | nums after | What happens | Why |
|---|---|---|---|---|---|---|
| 1 | k % n | - | - | [10, 20, 30, 40, 50, 60] | k = 8 % 6 = 2 | Rotating by 6 changes nothing, so a rotation by 8 is the same as a rotation by 2. |
| 2 | Reverse all | 0 | 5 | [60, 20, 30, 40, 50, 10] | Swap 10 and 60 | The first reversal swaps the two ends, then steps both inward. |
| 3 | Reverse all | 1 | 4 | [60, 50, 30, 40, 20, 10] | Swap 20 and 50 | Second swap of the whole-array reversal. |
| 4 | Reverse all | 2 | 3 | [60, 50, 40, 30, 20, 10] | Swap 30 and 40 | Now start becomes 3 and end becomes 2, so this reversal stops. B = [50, 60] is in front, but backwards. |
| 5 | Reverse first k | 0 | 1 | [50, 60, 40, 30, 20, 10] | Swap 60 and 50 | Reversing indexes 0 to k - 1 puts B back in its original order. |
| 6 | Reverse the rest | 2 | 5 | [50, 60, 10, 30, 20, 40] | Swap 40 and 10 | Now reverse indexes k to n - 1, the backwards copy of A. |
| 7 | Reverse the rest | 3 | 4 | [50, 60, 10, 20, 30, 40] | Swap 30 and 20 | The last swap. start passes end, and the rotation is done. |
The result is [50, 60, 10, 20, 30, 40], the input rotated right by 2. It took 6 swaps: 3 for the whole array, 1 for the first block, and 2 for the rest.
Compared with other ways
When to pick something else
| Approach | Time | Extra memory | Choose it when |
|---|---|---|---|
| Array rotation | O(n) | O(1) | You must rotate in place with no extra array. |
| Copy into a new array | O(n) | O(n) | You may return a new array; the code is one line with (i + k) % n. |
| Keep an offset, don't move items | O(1) | O(1) | You only read the rotated view, like a carousel or a ring buffer, so changing a start index is enough. |
Pop and unshift k times | O(n · k) | O(1) | Only for tiny arrays and k of 1 or 2. |
Extra memory: O(1): only n, k, start, and end. The copying approach uses O(n) for the new array.
How the steps grow
- Array rotation, Copy into a new array
O(n) - Keep an offset, don't move items
O(1) - Pop and unshift
ktimesO(n · k)
| Approach | n = 10 | n = 1,000 | n = 1,000,000 |
|---|---|---|---|
| Array rotation | 10 | 1,000 | 1 million |
| Copy into a new array | 10 | 1,000 | 1 million |
| Keep an offset, don't move items | 1 | 1 | 1 |
Pop and unshift k times | 100 | 1 million | 1 trillion |
Inputs that need care
5 tricky inputs
- An empty array:
nums = [] - The early
returnruns beforek % n, which would otherwise bek % 0, which isNaN. kis 0 or a multiple ofnk % nis 0. The array ends unchanged, but the code still reverses it twice. Addif (k === 0) return numsto skip that work.kbigger thann:k = 8,n = 6k % nreduces it to 2 before any reversal, as in the trace.- A negative
k:k = -1on[1, 2, 3, 4, 5, 6] -1 % 6is-1in JavaScript, soreverse(nums, -1, 5)runs. The array ends as[2, 3, 4, 5, 6, undefined], and the1is stored on a property named"-1". Use((k % n) + n) % n, which also turns a left rotation into the matching right one.- One item:
nums = [7] k % 1is 0, every reversal hasstart >= end, and the array stays[7].
Variations and follow-ups
Twists interviewers add
Moving items along cycles
Another in-place method picks up nums[0], drops it at its target k slots ahead, picks up the item that was there, and keeps going around. The array splits into a number of such cycles equal to the greatest common divisor of n and k. Each item moves exactly once.
Is one string a rotation of another?
b is a rotation of a exactly when they have the same length and b appears inside a + a. For example, "lopab" is in "ablopablop", so it is a rotation of "ablop".
Rotating a linked list
Find the length and the tail, link the tail to the head to make a loop, then walk n - k steps and cut the loop there. The node after the cut is the new head. No values move at all.
In an interview
Spot it, explain it, answer follow-ups
- Spot it from "rotate", "shift right by
k", "circular", and "in place" or "O(1)extra space". - Explain it with blocks: "
A Bmust becomeB A; reversing the whole thing swaps the blocks, and reversing each block fixes them." - Test by hand:
k = 0,klarger thann, and an array of one item. Reducekwithk % nbefore anything else. - A common follow-up is "rotate left". Answer: rotate right by
n - k, or reverse the firstk, then the rest, then everything.
Where frontend code uses it
The same idea in real UI code
- Image carousels and sliders rotate their list of slides; keeping a start index and using
%avoids moving items at all. - Calendars rotate the weekday labels so the week starts on Monday or Sunday depending on the user's locale.
- Ring buffers for logs or recent items wrap their write position around the end of a fixed-size array.