Skip to content
← All posts

Rotate Array: The Triple Reverse Trick

7 min read
leetcodeproblemmediumarrays

LeetCode Rotate Array is one of those problems where the brute force is obvious, but the optimal solution is genuinely elegant. You are given an integer array nums and an integer k. Rotate the array to the right by k steps. That means the last k elements wrap around to the front.

Simple enough to understand. But doing it in O(1) extra space? That is where the triple reverse trick comes in, and it is one of the most satisfying "aha" moments in all of LeetCode.

The problem

Given nums = [1, 2, 3, 4, 5, 6, 7] and k = 3, the result should be [5, 6, 7, 1, 2, 3, 4]. The last three elements (5, 6, 7) move to the front, and everything else shifts right to make room.

Before10213243546576last k = 3After5671234
Rotating [1, 2, 3, 4, 5, 6, 7] right by k = 3. The last 3 elements move to the front.

One important detail: k can be larger than the array length. If nums has 7 elements and k = 10, that is the same as rotating by 3 (since 10 % 7 = 3). So the first thing you should always do is k = k % len(nums).

Approach 1: Extra array (the obvious way)

The simplest approach is to create a new array and place each element at its rotated position. Element at index i goes to index (i + k) % n.

def rotate(nums: list[int], k: int) -> None:
    n = len(nums)
    k = k % n
    rotated = [0] * n
    for i in range(n):
        rotated[(i + k) % n] = nums[i]
    nums[:] = rotated

This works fine. O(n) time, O(n) space. But the problem explicitly asks: "Could you do it in-place with O(1) extra space?" So we need something better.

The nums[:] = rotated line is important. You cannot write nums = rotated because that just rebinds the local variable. You need to modify the list in-place so the caller sees the change. The slice assignment nums[:] replaces the contents of the original list.

Approach 2: Cyclic replacements

Another approach is to move elements one at a time in cycles. Start at index 0, move its value to index k, move whatever was at k to 2k, and so on until you land back at the start. If you have not moved all elements, start the next cycle from index 1.

def rotate(nums: list[int], k: int) -> None:
    n = len(nums)
    k = k % n
    count = 0
    start = 0

    while count < n:
        current = start
        prev = nums[start]
        while True:
            next_idx = (current + k) % n
            nums[next_idx], prev = prev, nums[next_idx]
            current = next_idx
            count += 1
            if current == start:
                break
        start += 1

This is O(n) time and O(1) space, which is what we want. But honestly, it is hard to get right under pressure. The cycle logic with the start variable and the count tracker is error-prone. There are subtle edge cases when k divides n evenly.

It works, but there is a much cleaner way.

Approach 3: The triple reverse trick (optimal and clean)

Here is the key insight. Rotating an array by k positions is the same as:

  1. Reverse the entire array
  2. Reverse the first k elements
  3. Reverse the remaining n - k elements

That is it. Three reverses, each one in-place, and you are done.

Why does this work? Think of the array as two blocks: the first n - k elements (call them A) and the last k elements (call them B). You want to go from [A, B] to [B, A].

  • Reversing everything gives you [B_reversed, A_reversed]
  • Reversing the first k elements fixes B: [B, A_reversed]
  • Reversing the rest fixes A: [B, A]

Each reverse is a simple swap loop that runs in O(n) time total and uses zero extra space.

def rotate(nums: list[int], k: int) -> None:
    n = len(nums)
    k = k % n

    def reverse(left: int, right: int) -> None:
        while left < right:
            nums[left], nums[right] = nums[right], nums[left]
            left += 1
            right -= 1

    reverse(0, n - 1)       # reverse all
    reverse(0, k - 1)       # reverse first k
    reverse(k, n - 1)       # reverse the rest

Clean. Short. Easy to remember. Easy to type from memory.

The triple reverse trick is the same idea behind rotating a string. If you ever need to left-rotate instead of right-rotate, just change the order: reverse first k, reverse the rest, then reverse all. Same three reverses, different sequence.

Visual walkthrough: the triple reverse step by step

Let's trace through nums = [1, 2, 3, 4, 5, 6, 7] with k = 3. Watch how each reverse brings us closer to the answer.

Original array (k = 3)

10213243546576

Blue = first n-k elements, green = last k elements. Goal: move green to the front.

Step 1: Reverse the entire array

70615243342516

All elements reversed. The last k are now at the front, but in the wrong order.

Step 2: Reverse the first k elements (indices 0 to 2)

50617243342516

First 3 elements are now in the correct order: [5, 6, 7].

Step 3: Reverse the rest (indices 3 to 6)

50617213243546

Done! The remaining elements are also in the correct order. Three reverses, zero extra space.

Three passes over the array. Each element gets swapped exactly once per reverse. Total work: O(n). Extra memory: just the two pointers and one temp variable for swapping. That is O(1).

Complexity comparison

ApproachTimeSpaceClean to code?
Extra arrayO(n)O(n)Yes
Cyclic replacementsO(n)O(1)Tricky
Triple reverseO(n)O(1)Yes

The triple reverse wins on every axis. Same optimal time and space as the cyclic approach, but far easier to implement correctly.

The building blocks

This problem breaks down into one core reusable brick:

Reverse in-place

The ability to reverse a subarray between two indices using a two-pointer swap loop. You start with left at the beginning and right at the end, swap the values, and walk both pointers inward until they meet.

def reverse(arr: list[int], left: int, right: int) -> None:
    while left < right:
        arr[left], arr[right] = arr[right], arr[left]
        left += 1
        right -= 1

This micro-pattern is the backbone of the triple reverse trick, but it shows up everywhere:

  • Reverse String (LeetCode 344) is literally just this brick, applied to the whole array.
  • Reverse Words in a String (LeetCode 151) uses the same "reverse all, then reverse parts" idea at the word level.
  • Palindrome checking uses reverse (or two-pointer convergence, which is the same movement pattern) to compare a sequence against itself.
  • Next Permutation (LeetCode 31) reverses a suffix as its final step.

Once you can write a subarray reverse without thinking, you can compose it into solutions for all of these problems. The triple reverse trick for Rotate Array is just three calls to the same function.

Common mistakes

1. Forgetting to handle k >= n. If k equals the array length, no rotation is needed. If k is larger, you need k = k % n. Without this, you will access indices out of bounds or do unnecessary work.

2. Off-by-one errors in reverse boundaries. The three reverse calls are reverse(0, n-1), reverse(0, k-1), and reverse(k, n-1). Getting those boundaries wrong by one position will produce the wrong result. Trace through a small example to double-check.

3. Writing nums = nums[n-k:] + nums[:n-k]. This creates a new list and rebinds the local variable. The original list is unchanged, so LeetCode will say your output is wrong. You need nums[:] = ... to modify the list in-place, or better yet, use the triple reverse which does not allocate at all.

When k is 0 (or a multiple of n), the array should not change at all. Make sure your solution handles this. With k = k % n, if the result is 0 you can return early and skip all three reverses.

When to reach for this pattern in interviews

The triple reverse trick applies whenever you need to rearrange contiguous blocks of an array without extra space. Look for these signals:

  • The problem says "rotate" or "shift" elements by some amount
  • You need to move a prefix or suffix of an array to the other end
  • The constraint says O(1) extra space but O(n) time is fine
  • You are working with a circular arrangement where elements wrap around

If the problem involves rearranging blocks and you are not allowed extra memory, think "reverse."

Related posts

  • The Two Pointers Pattern - The reverse-in-place brick is a two-pointer technique. Understanding two pointers makes the reverse trivial.
  • Merge Sorted Array - Another in-place array problem where the trick is working from the right direction.
  • Product of Array Except Self - An array problem where clever use of existing space avoids extra allocation.

The triple reverse trick is one of those things that feels like magic the first time you see it. But there is no magic. It is just the reverse-in-place brick, applied three times in the right order. The hard part is not understanding it. The hard part is producing it from memory when you are staring at a blank editor in an interview.

That is why drilling matters. You type the reverse function from scratch. You type the three calls. You do it again in three days, then a week later, then two weeks after that. After a few reps, the trick is not something you "remember." It is something you just do.