Back to Stream Practice: Collections & Numbers
Q6Question 6 of 11

Reverse an integer array without using inbuilt functions

Key Concepts
  • Two-pointer swap: left=0, right=n-1, swap arr[left] and arr[right], move inward until they meet
  • In-place reversal is O(n) time and O(1) space
  • Stream approach: IntStream.rangeClosed(1, n).map(i -> arr[n - i]).toArray() creates a NEW reversed array
  • The stream approach is O(n) time but O(n) space because it creates a new array
  • The middle element of an odd-length array stays in place because the pointers meet at the middle
  • Streams avoid mutation by producing a new array, which is safer for banking audit trails

Definition

Use two pointers (left and right) that swap elements and move inward for in-place O(1) space reversal, or use IntStream index mapping for a new reversed array.
  • Two-pointer swap: start left at 0 and right at n-1, swap arr[left] and arr[right], increment left and decrement right until they meet.
  • In-place: O(n/2) swaps = O(n) time, O(1) extra space.
  • Stream approach: IntStream.rangeClosed(1, n).map(i -> arr[n - i]).toArray() reads elements from the end and builds a NEW array.
  • The stream approach does not mutate the source array, which is safer when the original must be preserved.
  • For odd-length arrays, the middle element is not swapped because the pointers meet at the center.

A stack of bank cheques numbered [001, 002, 003, 004, 005] needs to be reversed. The two-pointer approach swaps the top and bottom cheques (001 and 005), then the second and second-to-last (002 and 004), and the middle cheque (003) stays in place.

Understanding the Concepts

How do you reverse an array in-place with two pointers?

JAVA
package com.bank.util;

import java.util.Arrays;
import java.util.stream.IntStream;

public class ReverseArrayDemo {
    public static void main(String[] args) {
        int[] cheques = {1, 2, 3, 4, 5};

        // Two-pointer in-place reversal
        int left = 0;
        int right = cheques.length - 1;
        while (left < right) {
            int temp = cheques[left];
            cheques[left] = cheques[right];
            cheques[right] = temp;
            left++;
            right--;
        }

        System.out.println("Reversed: " + Arrays.toString(cheques));
    }
}
TEXT
Reversed: [5, 4, 3, 2, 1]

How do you reverse using streams?

JAVA
int[] original = {1, 2, 3, 4, 5};
int n = original.length;

// Stream approach: new array, source unchanged
int[] reversed = IntStream.rangeClosed(1, n)
    .map(i -> original[n - i])
    .toArray();

System.out.println("Original: " + Arrays.toString(original));
System.out.println("Reversed: " + Arrays.toString(reversed));
TEXT
Original: [1, 2, 3, 4, 5]
Reversed: [5, 4, 3, 2, 1]

The stream approach produces a NEW array. The original is not mutated.

How do the two approaches compare?

| Feature | Two-pointer | Stream |
|---------|------------|--------|
| Time | O(n) | O(n) |
| Space | O(1) in-place | O(n) new array |
| Mutates source | Yes | No |
| Readability | Imperative loop | Declarative pipeline |
| Thread safety | Unsafe (mutates) | Safe (immutable result) |

What about reversing a list of strings?

JAVA
import java.util.List;
import java.util.Collections;

List<String> branches = List.of("Mumbai", "Delhi", "Chennai");

// Stream approach
List<String> reversed = IntStream.rangeClosed(1, branches.size())
    .mapToObj(i -> branches.get(branches.size() - i))
    .toList();
// [Chennai, Delhi, Mumbai]

What are edge cases?

JAVA
// Empty array: no swaps needed
int[] empty = {};
// left=0, right=-1, loop does not execute

// Single element: no swap needed
int[] single = {42};
// left=0, right=0, left < right is false, loop does not execute

// Even-length: all elements swap
int[] even = {1, 2, 3, 4};
// Swap (1,4) then (2,3). Result: [4, 3, 2, 1]

// Odd-length: middle stays
int[] odd = {1, 2, 3, 4, 5};
// Swap (1,5) then (2,4). 3 stays. Result: [5, 4, 3, 2, 1]

What about using a Stack?

JAVA
import java.util.ArrayDeque;
import java.util.Deque;

// Stack approach: push all, then pop all
int[] arr = {1, 2, 3, 4, 5};
Deque<Integer> stack = new ArrayDeque<>();
for (int val : arr) stack.push(val);
for (int i = 0; i < arr.length; i++) arr[i] = stack.pop();
// [5, 4, 3, 2, 1] - O(n) time, O(n) space

What about Collections.reverse for lists?

JAVA
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

List<String> mutable = new ArrayList<>(List.of("Mumbai", "Delhi", "Chennai"));
Collections.reverse(mutable);
// [Chennai, Delhi, Mumbai]

// WRONG: List.of returns unmodifiable list
// Collections.reverse(List.of("A", "B")); // UnsupportedOperationException!

What should a senior engineer know?

  • The stream approach using IntStream.rangeClosed avoids autoboxing because it stays in the IntStream pipeline and produces a primitive int[] via toArray().
  • In banking, the non-mutating stream approach is preferred when the original order is part of the audit trail. The ledger stores balances oldest-first, but the statement shows newest-first.
  • Collections.reverse(list) reverses a list in place but only works on mutable lists. List.of(...) returns an unmodifiable list, so Collections.reverse throws UnsupportedOperationException.

Visual Overview

DIAGRAM
  Two-pointer approach:

  [1, 2, 3, 4, 5]
   L              R     swap(1,5)
  [5, 2, 3, 4, 1]
      L        R        swap(2,4)
  [5, 4, 3, 2, 1]
         LR             L >= R → stop

  Stream approach:

  IntStream.rangeClosed(1, 5)
  i=1 → arr[5-1] = arr[4] = 5
  i=2 → arr[5-2] = arr[3] = 4
  i=3 → arr[5-3] = arr[2] = 3
  i=4 → arr[5-4] = arr[1] = 2
  i=5 → arr[5-5] = arr[0] = 1
  → [5, 4, 3, 2, 1]

Key Takeaway

Reversing an array without built-in functions uses two approaches. The two-pointer swap starts from both ends and moves inward: O(n) time, O(1) space, but mutates the original. The stream approach IntStream.rangeClosed(1, n).map(i -> arr[n - i]).toArray() reads from the end and builds a new array: O(n) time, O(n) space, but preserves the original.

At National Bank of India, the ledger stores end-of-day balances oldest-first, but a statement must show newest-first. The stream approach produces the display order without altering the stored ledger, which is important for audit compliance.

Remember one sentence: two-pointer swap is O(1) space but mutates the source; IntStream index mapping produces a new reversed array without mutation.

---

Share
Use ← → arrow keys to navigate