Skip to content

Array Manipulation: Code Templates in 6 Languages

If you have not read the concept guide yet, start there for the intuition and complexity analysis. This page gives you the code you can memorize and adapt during an interview. Every template here runs in

O(N)
time with
O(1)
extra space unless otherwise noted.

Main Template: Two-Pointer Reversal

This is the most common array manipulation pattern and the building block for rotation, palindrome checks, and many string operations. Two pointers start at opposite ends and work inward, swapping each pair once.

Use this for Reverse String and as a helper in Rotate Array and similar problems.

function reverse(arr, start = 0, end = arr.length - 1) {
    while (start < end) {
        // Swap the outer pair so both elements land
        // on the correct side of the reversed segment
        [arr[start], arr[end]] = [arr[end], arr[start]];
        start++;
        end--;
    }
}
Templates only help if you can recall them without staring at the screen. Turn these snippets into flashcards for daily mobile review.

Code Breakdown

Key Variables

  • start / left: the left boundary of the segment to reverse. Points to the next unsettled element from the left side.
  • end / right: the right boundary. Points to the next unsettled element from the right side.
  • temp (swap): in languages without destructuring assignment (Java, C++), a temporary variable holds one value during the swap. Destructuring in Python, JavaScript, and Go makes this implicit.

Visual Mechanism

    stateDiagram-v2
    [*] --> Initialize: start = 0, end = n-1
    Initialize --> Swap: start < end
    Swap --> MovePointers: arr[start] <-> arr[end]
    MovePointers --> Swap: start++, end--
    Swap --> Done: start >= end
    Done --> [*]
  

Critical Sections

The initialization sets the range. Defaulting to the whole array works for a simple reversal, but the start and end parameters make this template reusable as a helper. Rotate Array, for example, calls reverse three times on different segments.

The swap is the only operation that touches the data. Destructuring assignment in Python, JavaScript, and Go is clean and avoids a temporary variable. In Java and C++, the temp is explicit.

The termination condition start < end stops before the pointers cross. Using <= would swap the middle element with itself in odd-length arrays and, worse, re-swap already-settled pairs in even-length arrays once the pointers have passed each other.

Variations

1. Array Rotation (Three-Reversal)

Reversing three segments in sequence produces a right rotation by k steps. The trick works because each reversal undoes part of the previous one, and the three together move elements from the tail to the head without allocating a second array.

Use this for Rotate Array .

function rotate(nums, k) {
    k = k % nums.length;
    const reverse = (arr, start, end) => {
        while (start < end) {
            [arr[start], arr[end]] = [arr[end], arr[start]];
            start++;
            end--;
        }
    };
    // Reverse all, then reverse each half separately.
    // This moves the last k elements to the front.
    reverse(nums, 0, nums.length - 1);
    reverse(nums, 0, k - 1);
    reverse(nums, k, nums.length - 1);
}

Visual

    graph LR
    I[Original] --> R1[Reverse All]
    R1 --> R2[Reverse First k]
    R2 --> R3[Reverse Rest]
    R3 --> F[Rotated]
  

2. Dutch National Flag (Three-Way Partition)

When an array contains three distinct values, three pointers can sort it in one pass. The technique extends naturally to k-way partitions with k pointers.

Use this for Sort Colors .

function sortColors(nums) {
    let low = 0, mid = 0, high = nums.length - 1;

    while (mid <= high) {
        if (nums[mid] === 0) {
            // 0 belongs on the left. Swap it to the low region
            // and advance both pointers because the new value
            // at mid came from low and has already been seen.
            [nums[low], nums[mid]] = [nums[mid], nums[low]];
            low++;
            mid++;
        } else if (nums[mid] === 1) {
            mid++; // 1 belongs in the middle, skip it
        } else {
            // 2 belongs on the right. Swap with high and shrink
            // the high region, but do not advance mid because
            // the new value at mid came from high and is unseen.
            [nums[mid], nums[high]] = [nums[high], nums[mid]];
            high--;
        }
    }
}

Visual

    graph TD
    S["Scan with mid pointer"] --> |"nums[mid] == 0"| L["Swap to low, low++, mid++"]
    S --> |"nums[mid] == 1"| M["Skip, mid++"]
    S --> |"nums[mid] == 2"| R["Swap to high, high--"]
  

3. Move Zeroes (Write Pointer)

A single write pointer tracks where the next non-zero element should land. This pattern extends to any conditional filtering where you keep some elements and push others to one end.

Use this for Move Zeroes .

function moveZeroes(nums) {
    let insertPos = 0; // next position for a non-zero element
    for (let i = 0; i < nums.length; i++) {
        if (nums[i] !== 0) {
            // Swap non-zero to the front. The zero that was
            // at insertPos moves right, which is fine because
            // all zeros should end up at the tail.
            [nums[insertPos], nums[i]] = [nums[i], nums[insertPos]];
            insertPos++;
        }
    }
}

Visual

    graph LR
    I["Iterate with i"] --> C{"arr[i] != 0?"}
    C -->|Yes| S[Swap to insertPos, insertPos++]
    C -->|No| N[Skip]
  

4. Kadane’s Algorithm

Kadane’s algorithm replaces pointers with running accumulators. At each position you decide whether to extend the current subarray or start fresh.

Use this for Maximum Subarray .

function maxSubArray(nums) {
    // The first element is both the best subarray seen so far
    // and the best subarray ending at position 0 by definition.
    let maxSoFar = nums[0];
    let maxEndingHere = nums[0];

    for (let i = 1; i < nums.length; i++) {
        // Either extend the existing subarray or start a new one
        // at the current element, whichever is larger.
        maxEndingHere = Math.max(nums[i], maxEndingHere + nums[i]);
        maxSoFar = Math.max(maxSoFar, maxEndingHere);
    }
    return maxSoFar;
}

Visual

    graph LR
    P[Previous Sum] --> D{Extend or Start New?}
    D -->|Extend| N1[Add current]
    D -->|Start new| N2[Current element]
    N1 --> G{Update global max?}
    N2 --> G
  
Each variation above is a separate review card in the app. Drill them individually so you do not mix up the conditions under pressure.

Now head to the practice problems to apply these templates to real interview questions.

Now that you have the templates, the next step is application. Head to the practice problems or start reviewing these templates with spaced repetition .