Reverse an Array

Reverse the order of elements in an array in-place and return the modified array

Language Selection

Choose your preferred programming language

Showing: Python

Reverse an Array

Problem Statement

Given an array of integers, reverse the order of elements in the array. You can modify the array in-place or create a new array.

Input/Output Specifications

  • Input: An array of integers nums where 0 <= nums.length <= 10^5 and -10^9 <= nums[i] <= 10^9
  • Output: The same array with elements in reverse order

Constraints

  • The array can be empty
  • Array elements can be negative, positive, or zero
  • You should aim for an in-place solution for optimal space complexity

Examples

Example 1:

Input: nums = [1, 2, 3, 4, 5]
Output: [5, 4, 3, 2, 1]
Explanation: Elements are reversed in place.

Example 2:

Input: nums = [7, 9]
Output: [9, 7]
Explanation: Two elements are swapped.

Example 3:

Input: nums = []
Output: []
Explanation: Empty array remains empty.

Example 4:

Input: nums = [42]
Output: [42]
Explanation: Single element array remains unchanged.

Solution Approaches

Approach 1: Two Pointers (In-Place) - Optimal

Algorithm Explanation:

  1. Use two pointers: one at the start (left) and one at the end (right) of the array
  2. Swap the elements at these positions
  3. Move the left pointer forward and right pointer backward
  4. Continue until the pointers meet or cross each other
  5. Return the modified array

Implementation:

Python:

def reverse_array(nums):
    """
    Reverse array using two pointers approach
    Time: O(n)
    Space: O(1)
    """
    if not nums:
        return nums
    
    left = 0
    right = len(nums) - 1
    
    while left < right:
        # Swap elements at left and right positions
        nums[left], nums[right] = nums[right], nums[left]
        left += 1
        right -= 1
    
    return nums

# Alternative using built-in reverse
def reverse_array_builtin(nums):
    """
    Reverse array using built-in reverse method
    Time: O(n)
    Space: O(1)
    """
    nums.reverse()
    return nums

# Alternative using slicing (creates new array)
def reverse_array_slicing(nums):
    """
    Reverse array using slicing
    Time: O(n)
    Space: O(n)
    """
    return nums[::-1]

Java:

class Solution {
    /**
     * Reverse array using two pointers approach
     * Time: O(n)
     * Space: O(1)
     */
    public int[] reverseArray(int[] nums) {
        if (nums == null || nums.length <= 1) {
            return nums;
        }
        
        int left = 0;
        int right = nums.length - 1;
        
        while (left < right) {
            // Swap elements at left and right positions
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            
            left++;
            right--;
        }
        
        return nums;
    }
    
    // Alternative using Collections.reverse
    public Integer[] reverseArrayList(Integer[] nums) {
        List<Integer> list = Arrays.asList(nums);
        Collections.reverse(list);
        return list.toArray(new Integer[0]);
    }
}

Go:

// reverseArray - Reverse array using two pointers approach
// Time: O(n)
// Space: O(1)
func reverseArray(nums []int) []int {
    if len(nums) <= 1 {
        return nums
    }
    
    left := 0
    right := len(nums) - 1
    
    for left < right {
        // Swap elements at left and right positions
        nums[left], nums[right] = nums[right], nums[left]
        left++
        right--
    }
    
    return nums
}

// Alternative creating new slice
func reverseArrayNew(nums []int) []int {
    if len(nums) <= 1 {
        return nums
    }
    
    result := make([]int, len(nums))
    for i := 0; i < len(nums); i++ {
        result[i] = nums[len(nums)-1-i]
    }
    
    return result
}

JavaScript:

/**
 * Reverse array using two pointers approach
 * Time: O(n)
 * Space: O(1)
 */
function reverseArray(nums) {
    if (!nums || nums.length <= 1) {
        return nums;
    }
    
    let left = 0;
    let right = nums.length - 1;
    
    while (left < right) {
        // Swap elements at left and right positions
        [nums[left], nums[right]] = [nums[right], nums[left]];
        left++;
        right--;
    }
    
    return nums;
}

// Alternative using built-in reverse
function reverseArrayBuiltin(nums) {
    return nums.reverse();
}

// Alternative using reduce
function reverseArrayReduce(nums) {
    return nums.reduce((acc, curr, i) => {
        acc[nums.length - 1 - i] = curr;
        return acc;
    }, new Array(nums.length));
}

C#:

public class Solution {
    /// <summary>
    /// Reverse array using two pointers approach
    /// Time: O(n)
    /// Space: O(1)
    /// </summary>
    public int[] ReverseArray(int[] nums) {
        if (nums == null || nums.Length <= 1) {
            return nums;
        }
        
        int left = 0;
        int right = nums.Length - 1;
        
        while (left < right) {
            // Swap elements at left and right positions
            int temp = nums[left];
            nums[left] = nums[right];
            nums[right] = temp;
            
            left++;
            right--;
        }
        
        return nums;
    }
    
    // Alternative using Array.Reverse
    public int[] ReverseArrayBuiltin(int[] nums) {
        if (nums == null) return nums;
        Array.Reverse(nums);
        return nums;
    }
    
    // Alternative using LINQ
    public int[] ReverseArrayLinq(int[] nums) {
        if (nums == null) return nums;
        return nums.Reverse().ToArray();
    }
}

Complexity Analysis:

  • Time Complexity: O(n) - We visit each element at most once
  • Space Complexity: O(1) - Only using a constant amount of extra space for variables

Trade-offs:

  • In-place modification is memory efficient
  • Simple and intuitive algorithm
  • No additional data structures needed
  • Modifies the original array (consider if this is desired behavior)

Approach 2: Iterative with New Array

Algorithm Explanation:

  1. Create a new array of the same size
  2. Iterate through the original array from the end to the beginning
  3. Place each element in the new array from the start
  4. Return the new array

Implementation:

Python:

def reverse_array_new(nums):
    """
    Reverse array by creating new array
    Time: O(n)
    Space: O(n)
    """
    if not nums:
        return nums
    
    result = [0] * len(nums)
    
    for i in range(len(nums)):
        result[i] = nums[len(nums) - 1 - i]
    
    return result

Java:

class Solution {
    /**
     * Reverse array by creating new array
     * Time: O(n)
     * Space: O(n)
     */
    public int[] reverseArrayNew(int[] nums) {
        if (nums == null || nums.length == 0) {
            return nums;
        }
        
        int[] result = new int[nums.length];
        
        for (int i = 0; i < nums.length; i++) {
            result[i] = nums[nums.length - 1 - i];
        }
        
        return result;
    }
}

Go:

// reverseArrayNew - Reverse array by creating new array
// Time: O(n)
// Space: O(n)
func reverseArrayNew(nums []int) []int {
    if len(nums) == 0 {
        return nums
    }
    
    result := make([]int, len(nums))
    
    for i := 0; i < len(nums); i++ {
        result[i] = nums[len(nums)-1-i]
    }
    
    return result
}

JavaScript:

/**
 * Reverse array by creating new array
 * Time: O(n)
 * Space: O(n)
 */
function reverseArrayNew(nums) {
    if (!nums || nums.length === 0) {
        return nums;
    }
    
    const result = new Array(nums.length);
    
    for (let i = 0; i < nums.length; i++) {
        result[i] = nums[nums.length - 1 - i];
    }
    
    return result;
}

C#:

public class Solution {
    /// <summary>
    /// Reverse array by creating new array
    /// Time: O(n)
    /// Space: O(n)
    /// </summary>
    public int[] ReverseArrayNew(int[] nums) {
        if (nums == null || nums.Length == 0) {
            return nums;
        }
        
        int[] result = new int[nums.Length];
        
        for (int i = 0; i < nums.Length; i++) {
            result[i] = nums[nums.Length - 1 - i];
        }
        
        return result;
    }
}

Complexity Analysis:

  • Time Complexity: O(n) - We visit each element once
  • Space Complexity: O(n) - We create a new array of the same size

Trade-offs:

  • Preserves the original array
  • Requires additional memory
  • Good when you need to keep the original array unchanged
  • Slightly more cache-friendly for very large arrays

Key Insights

  • Two Pointers Pattern: This is a fundamental pattern for array problems that need to process elements from both ends
  • In-place vs New Array: Choose based on whether you need to preserve the original array
  • Swap Technique: The simultaneous swap is a common idiom in many languages
  • Edge Cases: Empty arrays and single-element arrays require special handling

Edge Cases

  1. Empty Array: [] → Returns []
  2. Single Element: [5] → Returns [5]
  3. Two Elements: [1, 2] → Returns [2, 1]
  4. All Same Elements: [3, 3, 3] → Returns [3, 3, 3]
  5. Large Array: Performance should remain consistent

How Solutions Handle Edge Cases:

  • Empty array: Check length before processing
  • Single element: Left and right pointers never enter the while loop
  • Two elements: One swap occurs, then pointers meet
  • All same: Algorithm works correctly, swapping identical values

Test Cases

def test_reverse_array():
    # Basic case
    assert reverse_array([1, 2, 3, 4, 5]) == [5, 4, 3, 2, 1]
    
    # Two elements
    assert reverse_array([7, 9]) == [9, 7]
    
    # Empty array
    assert reverse_array([]) == []
    
    # Single element
    assert reverse_array([42]) == [42]
    
    # All same elements
    assert reverse_array([5, 5, 5]) == [5, 5, 5]
    
    # Negative numbers
    assert reverse_array([-1, -2, -3]) == [-3, -2, -1]
    
    # Mixed positive and negative
    assert reverse_array([-1, 0, 1]) == [1, 0, -1]
    
    # Large array
    large_array = list(range(1000))
    expected = list(range(999, -1, -1))
    assert reverse_array(large_array) == expected
    
    print("All tests passed!")

test_reverse_array()

Follow-up Questions

  1. Reverse Subarray: How would you reverse only a portion of the array?
  2. Reverse in Groups: How would you reverse every k elements?
  3. Rotate vs Reverse: What’s the difference between rotation and reversal?
  4. Linked List: How would you adapt this for a linked list?
  5. String Reversal: How does string reversal differ from array reversal?

Common Mistakes

  1. Index Out of Bounds: Not handling empty arrays properly

    • Problem: Accessing nums[0] when array is empty
    • Solution: Check array length before processing
  2. Infinite Loop: Wrong loop condition

    • Problem: Using while left <= right instead of while left < right
    • Solution: Use strict inequality to prevent swapping middle element with itself
  3. Not Handling Edge Cases: Forgetting single element arrays

    • Problem: Unnecessary processing for arrays of length 0 or 1
    • Solution: Early return for these cases
  4. Modifying vs Creating: Confusion about in-place vs new array

    • Problem: Expecting original array to be unchanged when using in-place method
    • Solution: Clearly document behavior and choose appropriate method

Interview Tips

  1. Ask Clarifying Questions: Should the reversal be in-place or create a new array?
  2. Start Simple: Begin with the two-pointer approach - it’s optimal and intuitive
  3. Discuss Alternatives: Mention built-in methods but implement the manual approach
  4. Edge Cases First: Handle empty and single-element arrays early
  5. Space-Time Trade-offs: Discuss when in-place is better vs when preserving original is needed

Concept Explanations

Two Pointers Technique: This problem demonstrates the fundamental two-pointers pattern where pointers move toward each other from opposite ends. This pattern is essential for many array and string problems.

In-Place Operations: Reversing an array in-place showcases how to modify data structures without using additional memory, which is crucial for memory-constrained environments.

When to Apply: Use this pattern when you need to process elements from both ends of a sequence, such as palindrome checking, finding pairs, or any symmetric operations.