Skip to main content

Rotate Array Algorithm Solutions and Implementation Patterns

Comprehensive Java solutions for rotating arrays including optimal approaches, time complexity analysis, and practical implementation strategies for FAANG technical interviews.

The rotate array problem presents a classic algorithmic challenge where we must efficiently shift array elements by a given number of positions. This problem tests understanding of array operations, space-time trade-offs, and clean implementation skills that are essential for FAANG technical interviews.

1. Pattern Restatement

Clarifying questions to ask the interviewer:

  1. What are the constraints on the input array size? (e.g., is it bounded by 10⁵ or 10⁶?)
  2. Are duplicates allowed in the array?
  3. Should the result be returned as a new array or can we mutate the input array in-place?
  4. Can we assume that k (number of rotations) will always be non-negative?
  5. What is the target time complexity for follow-up? (e.g., O(n) time with O(1) space)

Restate the pattern or problem type in your own words: The Rotate Array problem asks us to shift all elements of an array to the right by k positions, where the last k elements wrap around to the beginning. This is a classic array manipulation problem that tests understanding of modular arithmetic, in-place operations, and algorithmic optimization.

Clarify the signal words and constraint shape that point to it:

  • Signal words: "rotate", "shift", "k positions right", "wrap around"
  • Constraint shape: Array input with integer k, where k can be larger than array length
  • The key constraint is that we need to handle cases where k > array length using modulo arithmetic

Note any assumptions you are making:

  • The array is 0-indexed
  • k can be larger than the array length (we should use modulo)
  • We can mutate the input array in-place for optimal space complexity
  • The rotation is to the right (positive direction)

Identify whether the pattern is best suited for static, streaming, or online scenarios if relevant: This pattern is primarily for static data processing where the entire array is available at once. It's not well-suited for streaming scenarios where elements arrive one-by-one, as rotation requires knowledge of the full array structure to perform efficient in-place operations. However, it can be part of a larger streaming pipeline where batched rotations are needed.

2. When to Use This Pattern

Signal words and constraint shapes in a problem statement that indicate this pattern:

  • "Rotate" or "shift" array elements
  • "Right by k positions" or "left by k positions"
  • Array rotation with specific number of steps
  • "Reverse" or "rearrange" elements in-place

Why this pattern fits better than the most common alternatives: The rotate array problem is fundamentally about reorganizing elements in a way that preserves their relative order while shifting positions. Unlike sorting or searching patterns, it requires maintaining the logical sequence of elements while applying a specific transformation. The in-place rotation approach is preferred over creating new arrays because it optimizes space complexity to O(1) while still achieving O(n) time complexity.

Conditions where a variation or related pattern applies instead:

  • When the rotation is by a single position, simpler reversal techniques can be applied
  • For very large arrays with memory constraints, chunked rotation approaches may be preferred
  • When the array is already sorted and rotation creates a rotated sorted array, binary search optimizations can apply

The core insight that makes this pattern work: The key insight is that rotating an array by k positions can be achieved through a three-step reversal process: reverse the entire array, then reverse the first k elements, and finally reverse the remaining n-k elements. This works because reversing preserves relative ordering while effectively shifting positions in a predictable mathematical way.

This pattern is particularly effective for static arrays where all elements are known upfront and the rotation count is fixed, making it ideal for scenarios where memory efficiency and time complexity are both critical constraints.

3. Approach Evolution

Interview communication script:

My first instinct is to do a simple simulation where I rotate the array one position at a time, but that's O(n×k) where k is the number of rotations, which could be up to n. That's inefficient because we're doing redundant work.

Let me think about how to optimize this. I notice that if I reverse the entire array, then reverse the first k elements and finally reverse the remaining elements, I can achieve the rotation in O(n) time with O(1) extra space. This is a classic three-step reversal approach.

I'm not sure if there's a better mathematical approach, but the reversal method is clean and intuitive. The key insight is that reversing creates a natural rotation effect when we break it into three parts.

Let me trace through this more carefully to make sure I understand the invariants.

Brute-force approach and why it is not ideal:

The naive approach would be to perform k individual rotations, where each rotation moves all elements one position right and the last element wraps around to the first position. This requires O(n×k) time complexity, which becomes problematic when k approaches n or when dealing with large arrays. For example, rotating an array of size 1000 by 999 positions would require nearly a million operations.

Improved approach and the key optimization:

The optimal approach uses the three-step reversal technique:

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

The key optimization is recognizing that we can achieve the same result by leveraging the mathematical property of rotations. When we reverse the entire array, then reverse two segments, we effectively "shift" elements to their correct rotated positions without having to move each element individually.

Final approach with step-by-step reasoning:

  1. First, handle edge cases where k might be larger than array length by taking modulo
  2. Reverse the entire array to get elements in reverse order
  3. Reverse only the first k elements to bring them to their correct rotated positions
  4. Reverse the remaining elements to complete the rotation

This works because:

  • Step 1 reverses everything: [1,2,3,4,5,6,7] → [7,6,5,4,3,2,1]
  • Step 2 reverses first k elements: [7,6,5,4,3,2,1] → [5,6,7,4,3,2,1]
  • Step 3 reverses remaining elements: [5,6,7,4,3,2,1] → [5,6,7,1,2,3,4]

Important invariants that must hold:

  • The modulo operation ensures k is within [0, n) range
  • After each reversal step, the relative order of elements within each segment is preserved correctly
  • The final array has elements in their rotated positions as required by the problem

4. Data Structure Choice

For the rotate array problem, the primary data structure used is a primitive array (int[] in Java).

Why Array is Chosen

  • Direct access: Arrays provide O(1) random access to elements, which is essential for efficient rotation operations
  • Memory locality: Elements are stored contiguously in memory, providing optimal cache performance
  • Simplicity: No need for complex data structure management or additional overhead

Time and Space Impact

  • Time Complexity: O(1) for access operations, O(n) for rotation operations (depending on approach)
  • Space Complexity: O(1) additional space when using in-place rotation techniques, O(n) when requiring temporary storage

Helper Structures

  • No additional helper structures are needed for the optimal in-place solution using reverse operations
  • The algorithm relies purely on index manipulation and element swapping within the original array
  • A simple integer variable k is used to track the effective rotation amount (normalized to array length)

The array-based approach is optimal because it leverages the fundamental property that rotation can be achieved through strategic reversal operations without requiring additional memory allocation for a new array structure.

5. Algorithm Walkthrough

Let me trace through the algorithm with a concrete example to demonstrate how it works step by step.

Example: nums = [1,2,3,4,5,6,7], k = 3

Step 1: Normalize k to handle cases where k > nums.length

  • k = 3 % 7 = 3 (no change needed)

Step 2: Reverse entire array

  • Before: [1,2,3,4,5,6,7]
  • After: [7,6,5,4,3,2,1]

Step 3: Reverse first k elements (first 3 elements)

  • Before: [7,6,5,4,3,2,1]
  • After: [5,6,7,4,3,2,1]

Step 4: Reverse remaining elements (last 4 elements)

  • Before: [5,6,7,4,3,2,1]
  • After: [5,6,7,1,2,3,4]

Why this works:

  • The key insight is that reversing in three steps effectively rotates the array
  • First reverse moves all elements to their "opposite" positions
  • Then reversing the first k elements brings the last k elements to the front in correct order
  • Finally reversing the remaining elements places the first n-k elements in their correct rotated positions

Edge case handling:

  • When k = 0, no rotation occurs (no operations needed)
  • When k equals array length, we get back to original array
  • When k > array length, modulo operation handles the wraparound correctly

The algorithm terminates correctly because each reversal step is deterministic and the three-step process guarantees that elements end up in their rotated positions.

6. Java Solution

public class RotateArray {
    /**
     * Rotates the array to the right by k positions using reverse method.
     * Time: O(n), Space: O(1)
     */
    public void rotate(int[] nums, int k) {
        if (nums == null || nums.length <= 1 || k == 0) {
            return;
        }
        
        int n = nums.length;
        // Handle cases where k > n
        k = k % n;
        
        // Step 1: Reverse entire array
        reverse(nums, 0, n - 1);
        
        // Step 2: Reverse first k elements
        reverse(nums, 0, k - 1);
        
        // Step 3: Reverse remaining elements from index k to end
        reverse(nums, k, n - 1);
    }
    
    /**
     * Helper method to reverse elements in array from start to end indices
     */
    private void reverse(int[] nums, int start, int end) {
        while (start < end) {
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start++;
            end--;
        }
    }
}

The solution uses the three-step reversal technique:

  1. Reverse entire array
  2. Reverse first k elements
  3. Reverse remaining elements from index k onwards

This approach is optimal with O(1) space complexity and O(n) time complexity, making it ideal for the constraints typically found in FAANG interviews. The key insight is that reversing in parts effectively rotates elements to their correct positions.

7. Complexity Analysis

Time Complexity: O(n)

The solution makes three passes through the array:

  1. First pass to reverse the entire array: O(n)
  2. Second pass to reverse the first k elements: O(k)
  3. Third pass to reverse the remaining n-k elements: O(n-k)

Since k < n, the overall time complexity is O(n + k + n-k) = O(n).

Space Complexity: O(1)

The algorithm uses only a constant amount of extra space for the temporary variables (indices and values). No additional data structures are created that scale with input size. The reversal is done in-place by swapping elements within the original array.

Why these bounds are correct:

The time complexity is optimal for this problem since we must examine each element at least once to achieve the rotation. The space complexity is optimal because the problem explicitly asks for an in-place solution, and we're not using any auxiliary data structures that grow with input size.

The solution is near-optimal as it achieves the best possible time complexity O(n) with constant space usage, which matches the theoretical lower bound for this operation. The approach avoids the O(n²) complexity that would result from naive shifting operations.

The algorithm's linear time complexity is achieved by leveraging the mathematical property that rotating right by k positions is equivalent to reversing the entire array, then reversing the first k elements, then reversing the remaining elements. This mathematical insight allows us to solve the problem in a single pass through each relevant segment.

8. Edge Cases & Pitfalls

Empty and Minimal Inputs

  • Empty array: nums = [], k = 3 → should return empty array
  • Single element: nums = [1], k = 1 → should return [1]
  • k = 0: No rotation needed, return original array
  • Array length equals k: Full rotation, return same array

Duplicate Values and Repeated States

  • Arrays with duplicate elements rotate correctly without affecting logic
  • When k is larger than array length, modulo operation handles duplicates properly

Boundary Conditions

  • k > nums.length: Must use k = k % nums.length to avoid redundant full rotations
  • k = nums.length: Same as no rotation, but must handle correctly
  • Negative k values: While problem typically assumes non-negative, if given, modulo with array length should normalize

Common Implementation Mistakes

  1. Not handling modulo correctly: Failing to use k % nums.length can cause incorrect rotations
  2. Modifying input array in-place: If problem requires preserving original, must make copy before rotation
  3. Off-by-one errors in index calculations: Particularly when implementing reverse operations or pointer movements
  4. Incorrect array bounds: Accessing nums[nums.length] or negative indices
  5. Not considering k = 0 case: Simple return without any rotation logic

Runtime Pitfalls

  • Using O(n) extra space unnecessarily: Some solutions create new arrays when in-place rotation is possible
  • Not optimizing k value: Failing to reduce k modulo array length causes unnecessary operations
  • Inefficient reversal logic: Not properly handling the three-step reverse process in the optimal solution

The key is to validate that rotation logic works correctly for all edge cases, particularly when k exceeds array bounds and when arrays have minimal size.

9. Alternative Approaches

There are several alternative approaches to solving the rotate array problem, each with different trade-offs:

1. Brute Force with Extra Space

public void rotate(int[] nums, int k) {
    int n = nums.length;
    k = k % n;
    int[] temp = new int[n];
    
    // Copy elements to their rotated positions
    for (int i = 0; i < n; i++) {
        temp[(i + k) % n] = nums[i];
    }
    
    // Copy back to original array
    System.arraycopy(temp, 0, nums, 0, n);
}

This approach is simple to understand but uses O(n) extra space and requires two passes through the array.

2. Three Reversals Approach (Alternative Implementation) Instead of reversing the entire array first, we can reverse in a different order:

public void rotate(int[] nums, int k) {
    int n = nums.length;
    k = k % n;
    
    // Reverse entire array
    reverse(nums, 0, n - 1);
    // Reverse first k elements
    reverse(nums, 0, k - 1);
    // Reverse remaining elements
    reverse(nums, k, n - 1);
}

private void reverse(int[] nums, int start, int end) {
    while (start < end) {
        int temp = nums[start];
        nums[start] = nums[end];
        nums[end] = temp;
        start++;
        end--;
    }
}

3. Cyclic Replacements

public void rotate(int[] nums, int k) {
    int n = nums.length;
    k = k % n;
    
    int count = 0; // number of elements rotated
    int start = 0;
    
    while (count < n) {
        int current = start;
        int prev = nums[start];
        
        do {
            int next = (current + k) % n;
            int temp = nums[next];
            nums[next] = prev;
            prev = temp;
            current = next;
            count++;
        } while (start != current);
        
        start++;
    }
}

Comparison and Trade-offs:

The three reversals approach is the most commonly preferred alternative as it's intuitive and efficient. The cyclic replacement approach has the same time complexity but is more complex to understand and implement correctly. The brute force approach is simpler but uses extra space.

The chosen solution (three reversals) is preferred because it's clean, easy to understand, and optimal in both time and space complexity. The cyclic replacement approach is more complex but uses minimal extra space and can be slightly faster in practice due to fewer array operations, though it's harder to reason about correctness.

The three reversals approach is the most maintainable and less error-prone of the alternatives, making it ideal for production code in a FAANG environment.

10. Test Cases

public class RotateArray {
    public void rotate(int[] nums, int k) {
        // Implementation here
    }
}

Sample Test Cases

Case 1: Basic rotation

  • Input: nums = [1,2,3,4,5,6,7], k = 3
  • Expected: [5,6,7,1,2,3,4]
  • Why: Three elements are rotated from the end to the beginning

Case 2: k larger than array length

  • Input: nums = [1,2,3], k = 4 (equivalent to k=1)
  • Expected: [3,1,2]
  • Why: When k > n, we only need to rotate by k % n positions

Case 3: k equals array length

  • Input: nums = [1,2,3], k = 3
  • Expected: [1,2,3]
  • Why: Full rotation returns to original array

Tricky Test Case

Case 4: k = 0

  • Input: nums = [1,2,3], k = 0
  • Expected: [1,2,3]
  • Why: No rotation should occur

Boundary Test Case

Case 5: Single element array

  • Input: nums = [1], k = 1
  • Expected: [1]
  • Why: Single element arrays should remain unchanged regardless of k value

Case 6: Empty array

  • Input: nums = [], k = 1
  • Expected: []
  • Why: Empty arrays should remain empty

These test cases cover the essential scenarios including edge cases and boundary conditions that help validate correctness of the rotation implementation.

11. Final Summary

The core idea is to efficiently rotate an array by reversing subarrays in O(1) extra space using the three-step reversal technique. This approach works because reversing the entire array, then reversing the first k elements and last (n-k) elements inverts the rotation effect perfectly. The solution is optimal with O(n) time and O(1) space complexity, making it ideal for scenarios where memory constraints are strict and the input array can be modified. The elegant use of mathematical properties of rotations makes this approach both efficient and easy to reason about, avoiding the need for additional data structures or complex indexing arithmetic.

Was this article helpful?

Topics in this article

More from DSA Patterns

  • DSA Patterns

    Mastering Prefix Sum Arrays in Java

    Comprehensive guide to prefix sum arrays with implementation examples, time complexity analysis, and practical use cases for FAANG interviews.

  • DSA Problems

    Three Sum Problem Solution and Algorithm Analysis

    Complete Java implementation of the three sum algorithm with optimal time complexity and space considerations for FAANG interviews.

Stay in the Loop

Get curated DSA patterns, coding problems, frontend and backend LLD/HLD, and AI/ML System Design insights delivered straight to your inbox. No spam, just focused interview and engineering content.