cf.completefrontend
ARRAYS & HASHING · CORE

Array rotation

Shift every item in an array by k places, wrapping around the end, in place with three reversals.

Time O(n)Space O(1)5 practice problemsStep-through picture

The 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.

How the example maps to the code
In the exampleIn the code
The trainnums
How many cars move to the frontk
Turning the whole train aroundreverse(nums, 0, n - 1)
Turning the front cars aroundreverse(nums, 0, k - 1)
Turning the remaining cars aroundreverse(nums, k, n - 1)

From the slow way to array rotation

  1. The obvious way to rotate right by k is to move the last item to the front, k times, with nums.unshift(nums.pop()). Each unshift shifts every item over by one, so that costs O(n × k). Copying each item into a new array at (i + k) % n is O(n) time but needs a second array.
  2. Look at the result as two blocks. Call the first n - k items A and the last k items B. Rotating right by k turns A B into B A. So the real question is how to swap two blocks of different sizes inside one array.
  3. 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: B ends up in front and A at the back. But each block now reads backwards.
  4. 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

  1. Let n = nums.length. If it's 0, there's nothing to do.
  2. Reduce k with k = k % n: rotating by n changes nothing.
  3. Reverse the whole array.
  4. Reverse the first k items (indexes 0 to k - 1).
  5. Reverse the remaining items (indexes k to n - 1).
  6. 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.

Loading the picture…
See every step at onceThe same run, laid out side by side
Drawing every step…

The code

Point at a note to light up the lines it explains.

  1. function rotateRight(nums, k) {
  2. const n = nums.length;
  3. if (n === 0) return nums;
  4. k = k % n;
  5. reverse(nums, 0, n - 1);
  6. reverse(nums, 0, k - 1);
  7. reverse(nums, k, n - 1);
  8. return nums;
  9. }
  10. function reverse(nums, start, end) {
  11. while (start < end) {
  12. [nums[start], nums[end]] = [nums[end], nums[start]];
  13. start++;
  14. end--;
  15. }
  16. }

How fast it is

TimeO(n)
Extra memoryO(1)

The three reversals swap each item at most twice in total. Only start, end, and k are stored.

  • Best caseO(n)

    Even k = 0 reverses the whole array twice: 6 swaps for 6 items, ending where it began. Return early when k is 0 to skip them.

  • Average caseO(n)

    About n swaps for any k, split across the three reversals.

  • Worst caseO(n)

    No k costs more than about n swaps, and a huge k is reduced first with k % n.

Common mistakes

  • Forgetting k = k % n. With k bigger than n, the reversals use indexes outside the array.
  • Reversing the first n - k items instead of the first k, which rotates left instead of right.
  • Rotating by moving the last item to the front k times with unshift(pop()). Each unshift shifts 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.
  • k can 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.

Not started

0 of 5 solved. Solve one to earn the bronze medal, half for silver, and all of them for gold.

Start practicing

Go 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

StepStepstartendnums afterWhat happensWhy
1k % n--[10, 20, 30, 40, 50, 60]k = 8 % 6 = 2Rotating by 6 changes nothing, so a rotation by 8 is the same as a rotation by 2.
2Reverse all05[60, 20, 30, 40, 50, 10]Swap 10 and 60The first reversal swaps the two ends, then steps both inward.
3Reverse all14[60, 50, 30, 40, 20, 10]Swap 20 and 50Second swap of the whole-array reversal.
4Reverse all23[60, 50, 40, 30, 20, 10]Swap 30 and 40Now start becomes 3 and end becomes 2, so this reversal stops. B = [50, 60] is in front, but backwards.
5Reverse first k01[50, 60, 40, 30, 20, 10]Swap 60 and 50Reversing indexes 0 to k - 1 puts B back in its original order.
6Reverse the rest25[50, 60, 10, 30, 20, 40]Swap 40 and 10Now reverse indexes k to n - 1, the backwards copy of A.
7Reverse the rest34[50, 60, 10, 20, 30, 40]Swap 30 and 20The 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
ApproachTimeExtra memoryChoose it when
Array rotationO(n)O(1)You must rotate in place with no extra array.
Copy into a new arrayO(n)O(n)You may return a new array; the code is one line with (i + k) % n.
Keep an offset, don't move itemsO(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 timesO(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

1101001k10k100k1M116324864input size n
Steps as the input grows, for Array rotation and the other approaches, on a scale where each line up is 10 times more steps.
  • Array rotation, Copy into a new array O(n)
  • Keep an offset, don't move items O(1)
  • Pop and unshift k times O(n · k)
About how many steps for bigger inputs
Approachn = 10n = 1,000n = 1,000,000
Array rotation101,0001 million
Copy into a new array101,0001 million
Keep an offset, don't move items111
Pop and unshift k times1001 million1 trillion

Inputs that need care

5 tricky inputs
An empty array: nums = []
The early return runs before k % n, which would otherwise be k % 0, which is NaN.
k is 0 or a multiple of n
k % n is 0. The array ends unchanged, but the code still reverses it twice. Add if (k === 0) return nums to skip that work.
k bigger than n: k = 8, n = 6
k % n reduces it to 2 before any reversal, as in the trace.
A negative k: k = -1 on [1, 2, 3, 4, 5, 6]
-1 % 6 is -1 in JavaScript, so reverse(nums, -1, 5) runs. The array ends as [2, 3, 4, 5, 6, undefined], and the 1 is 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 % 1 is 0, every reversal has start >= 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 B must become B A; reversing the whole thing swaps the blocks, and reversing each block fixes them."
  • Test by hand: k = 0, k larger than n, and an array of one item. Reduce k with k % n before anything else.
  • A common follow-up is "rotate left". Answer: rotate right by n - k, or reverse the first k, 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.

Related algorithms