Array Problems Solved: Two Pointer & Prefix Sum Techniques for Interviews

Complete array manipulation guide with two-pointer technique and prefix sums in Python. Master subarray problems, Kadane's algorithm, Dutch National Flag, and sliding window for coding interviews

📅 Published: February 18, 2025 ✏️ Updated: March 25, 2025 By Ojaswi Athghara
#arrays #two-pointers #prefix-sum #kadanes #dutch-flag #subarrays

Array Problems Solved: Two Pointer & Prefix Sum Techniques for Interviews

When I Finally "Got" Two Pointers

Arrays seemed simple until interview problems hit. "Find pair summing to target"—easy with nested loops, but O(n²). The interviewer asked: "Can you do better?"

That's when I learned the two-pointer technique, and suddenly O(n) solutions appeared everywhere. Then came prefix sums, and subarray problems that seemed impossible became trivial.

In this guide, I'll share the array patterns that transformed my interview performance. You'll learn when to use two pointers, when to precompute prefix sums, and how to recognize these patterns instantly.

Pattern 1: Two Pointers on Sorted Arrays

The most common array pattern. When array is sorted, two pointers can replace nested loops.

Two Sum in Sorted Array

def two_sum_sorted(arr, target):
    """
    Find pair summing to target in sorted array.
    Two pointers from both ends.
    """
    left, right = 0, len(arr) - 1

    while left < right:
        current_sum = arr[left] + arr[right]

        if current_sum == target:
            return [left, right]
        elif current_sum < target:
            left += 1  # Need larger sum
        else:
            right -= 1  # Need smaller sum

    return []  # No pair found

Time: O(n), Space: O(1)

Why it works: If sum too small, move left pointer (increases sum). If too large, move right pointer (decreases sum).

Three Sum

LeetCode #15 - 3Sum

def three_sum(nums):
    """
    Find all unique triplets summing to zero.
    Sort + two pointers for each element.
    """
    nums.sort()
    result = []

    for i in range(len(nums) - 2):
        # Skip duplicates for first element
        if i > 0 and nums[i] == nums[i - 1]:
            continue

        # Two pointers for remaining elements
        left, right = i + 1, len(nums) - 1
        target = -nums[i]

        while left < right:
            current_sum = nums[left] + nums[right]

            if current_sum == target:
                result.append([nums[i], nums[left], nums[right]])

                # Skip duplicates
                while left < right and nums[left] == nums[left + 1]:
                    left += 1
                while left < right and nums[right] == nums[right - 1]:
                    right -= 1

                left += 1
                right -= 1
            elif current_sum < target:
                left += 1
            else:
                right -= 1

    return result

Time: O(n²), Space: O(1)

Pattern: Fix one element, use two pointers for the rest. Extends to 4Sum, KSum!

Pattern 2: Two Pointers - Opposite Directions

Container With Most Water

LeetCode #11 - Container With Most Water

def max_area(height):
    """
    Find two lines that form container with most water.
    Two pointers: move the shorter line inward.
    """
    left, right = 0, len(height) - 1
    max_water = 0

    while left < right:
        # Calculate current area
        width = right - left
        current_height = min(height[left], height[right])
        current_area = width * current_height
        max_water = max(max_water, current_area)

        # Move pointer at shorter line
        if height[left] < height[right]:
            left += 1
        else:
            right -= 1

    return max_water

Key insight: Always move the pointer at the shorter line. Moving the taller one can't increase area!

Pattern 3: Two Pointers - Same Direction (Fast & Slow)

Remove Duplicates from Sorted Array

LeetCode #26 - Remove Duplicates from Sorted Array

def remove_duplicates(nums):
    """
    Remove duplicates in-place, return new length.
    Slow pointer for unique position, fast for scanning.
    """
    if not nums:
        return 0

    slow = 0  # Position for next unique element

    for fast in range(1, len(nums)):
        if nums[fast] != nums[slow]:
            slow += 1
            nums[slow] = nums[fast]

    return slow + 1  # Length of unique portion

Pattern: Slow pointer marks position to write, fast pointer scans ahead.

Move Zeroes

LeetCode #283 - Move Zeroes

def move_zeroes(nums):
    """
    Move all zeros to end, maintain relative order.
    Slow pointer for non-zero position.
    """
    slow = 0  # Position for next non-zero

    for fast in range(len(nums)):
        if nums[fast] != 0:
            nums[slow], nums[fast] = nums[fast], nums[slow]
            slow += 1

Same pattern: Slow pointer tracks where to place next valid element.

Pattern 4: Prefix Sums

Precompute cumulative sums to answer range queries in O(1).

Subarray Sum Equals K

LeetCode #560 - Subarray Sum Equals K

def subarray_sum(nums, k):
    """
    Count subarrays with sum equal to k.
    Use prefix sum + hash map.
    """
    count = 0
    prefix_sum = 0
    sum_count = {0: 1}  # sum -> count

    for num in nums:
        prefix_sum += num

        # Check if (prefix_sum - k) exists
        # If yes, found subarray(s) with sum k
        if prefix_sum - k in sum_count:
            count += sum_count[prefix_sum - k]

        # Add current prefix sum to map
        sum_count[prefix_sum] = sum_count.get(prefix_sum, 0) + 1

    return count

Why it works:sum[i:j] = prefix_sum[j] - prefix_sum[i-1] If prefix_sum[j] - prefix_sum[i-1] == k, then prefix_sum[i-1] = prefix_sum[j] - k

Time: O(n), Space: O(n)

Range Sum Query

class NumArray:
    """
    Precompute prefix sums for O(1) range queries.
    """

    def __init__(self, nums):
        self.prefix = [0]
        for num in nums:
            self.prefix.append(self.prefix[-1] + num)

    def sumRange(self, left, right):
        """Get sum of elements from index left to right."""
        return self.prefix[right + 1] - self.prefix[left]

Pattern: Build prefix sum array once, answer queries in O(1).

Pattern 5: Dutch National Flag (3-Way Partitioning)

Partition array into three sections using three pointers.

Sort Colors

LeetCode #75 - Sort Colors

def sort_colors(nums):
    """
    Sort array of 0s, 1s, 2s in-place.
    Dutch National Flag algorithm.
    """
    low, mid, high = 0, 0, len(nums) - 1

    while mid <= high:
        if nums[mid] == 0:
            # Swap with low, move both forward
            nums[low], nums[mid] = nums[mid], nums[low]
            low += 1
            mid += 1
        elif nums[mid] == 1:
            # Keep 1 in middle, move mid forward
            mid += 1
        else:  # nums[mid] == 2
            # Swap with high, move high back
            nums[mid], nums[high] = nums[high], nums[mid]
            high -= 1
            # Don't move mid (need to check swapped element)

Invariant:

  • [0, low): all 0s
  • [low, mid): all 1s
  • [mid, high]: unknown
  • (high, end]: all 2s

Time: O(n), Space: O(1)

Pattern 6: Kadane's Algorithm (Maximum Subarray)

Find maximum sum subarray using dynamic programming thinking.

Maximum Subarray

LeetCode #53 - Maximum Subarray

def max_subarray(nums):
    """
    Find maximum sum of contiguous subarray.
    Kadane's algorithm: track current and global max.
    """
    current_max = global_max = nums[0]

    for num in nums[1:]:
        # Either extend current subarray or start new
        current_max = max(num, current_max + num)
        global_max = max(global_max, current_max)

    return global_max

Key insight: At each position, decide: extend current subarray or start fresh?

Time: O(n), Space: O(1)

Maximum Product Subarray

def max_product(nums):
    """
    Maximum product subarray (handles negatives).
    Track both max and min (negative * negative = positive).
    """
    if not nums:
        return 0

    max_prod = min_prod = result = nums[0]

    for num in nums[1:]:
        # Negative flips max and min
        if num < 0:
            max_prod, min_prod = min_prod, max_prod

        max_prod = max(num, max_prod * num)
        min_prod = min(num, min_prod * num)
        result = max(result, max_prod)

    return result

Clever twist: Track both max and min because negatives can flip them!

Pattern 7: In-Place Array Manipulation

Rotate Array

LeetCode #189 - Rotate Array

def rotate(nums, k):
    """
    Rotate array right by k steps in-place.
    Reverse three times.
    """
    n = len(nums)
    k = k % n  # Handle k > n

    # Helper: reverse subarray
    def reverse(left, right):
        while left < right:
            nums[left], nums[right] = nums[right], nums[left]
            left += 1
            right -= 1

    # Reverse entire array
    reverse(0, n - 1)
    # Reverse first k elements
    reverse(0, k - 1)
    # Reverse remaining elements
    reverse(k, n - 1)

Magic: Three reverses achieve rotation! [1,2,3,4,5,6,7] rotate 3:

  1. Reverse all: [7,6,5,4,3,2,1]
  2. Reverse first 3: [5,6,7,4,3,2,1]
  3. Reverse last 4: [5,6,7,1,2,3,4]

Pattern 8: Product of Array Except Self

Product Except Self

LeetCode #238 - Product of Array Except Self

def product_except_self(nums):
    """
    Product of all elements except self, without division.
    Use left and right products.
    """
    n = len(nums)
    result = [1] * n

    # Build left products
    left_product = 1
    for i in range(n):
        result[i] = left_product
        left_product *= nums[i]

    # Build right products and combine
    right_product = 1
    for i in range(n - 1, -1, -1):
        result[i] *= right_product
        right_product *= nums[i]

    return result

Insight: result[i] = (product of all left) × (product of all right)

Time: O(n), Space: O(1) excluding output

The Array Pattern Decision Tree

1. Need to find pair/triplet with sum?

  • Array sorted → Two pointers
  • Array unsorted → Hash map or sort first

2. Need to process subarrays?

  • Fixed size → Sliding window
  • Variable size conditions → Sliding window
  • Sum queries → Prefix sums
  • Maximum subarray → Kadane's algorithm

3. Need to partition array?

  • Two groups → Two pointers (same direction)
  • Three groups → Dutch National Flag

4. Need in-place manipulation?

  • Remove elements → Two pointers (fast & slow)
  • Rotate/reverse → Multiple reverses
  • Swap/rearrange → Multiple passes

Common Array Mistakes

Mistake 1: Not Handling Edge Cases

# Always check:
if not nums:  # Empty array
    return default_value
if len(nums) == 1:  # Single element
    return nums[0]

Mistake 2: Index Out of Bounds

# WRONG
for i in range(len(arr)):
    if arr[i] == arr[i + 1]:  # Crashes at last element!

# RIGHT
for i in range(len(arr) - 1):
    if arr[i] == arr[i + 1]:

Mistake 3: Modifying While Iterating

# WRONG: Size changes during iteration
for num in arr:
    if condition:
        arr.remove(num)

# RIGHT: Use two pointers or create new array

My Practice Strategy

Week 1: Two Pointers

  • Master all variations (opposite, same direction, three pointers)
  • 20-30 problems
  • Focus on sorted vs unsorted

Week 2: Prefix Sums and Subarrays

  • Range queries, subarray sums
  • Kadane's algorithm variations
  • 15-20 problems

Week 3: In-Place Manipulation

  • Dutch National Flag, rotations
  • Remove duplicates variations
  • 15-20 problems

Week 4: Mixed Practice

  • 40+ problems across all patterns
  • Practice recognizing patterns quickly
  • Time yourself

Real Interview Success

I was asked: "Find longest subarray with sum ≤ k."

My approach:

  1. "Subarray with condition" → Sliding window
  2. Expand window, contract when sum > k
  3. Track maximum length

Coded in 10 minutes using sliding window pattern!

Conclusion: Your Array Mastery Roadmap

Arrays aren't just about loops—they're about patterns:

  1. Two pointers - Replace nested loops with O(n)
  2. Prefix sums - Answer range queries in O(1)
  3. Sliding window - Process subarrays efficiently
  4. Kadane's algorithm - Maximum subarray problems
  5. In-place manipulation - Save space with clever swaps

Master these patterns, and array problems become pattern matching exercises.

Within 3-4 weeks of focused practice, you'll recognize which pattern to use within seconds of reading a problem.

Remember: arrays are the foundation. Master them, and everything else becomes easier!

Happy coding, and may your arrays always be sorted!


If you found this guide helpful, share it with others learning algorithms. Array patterns are fundamental to interview success. If this guide helped you master array patterns or ace your coding interview, I'd love to hear about it! Connect with me on Twitter or LinkedIn.

Support My Work

If this guide helped you master array patterns, understand two pointers and prefix sums, or ace array interview questions, I'd really appreciate your support! Creating comprehensive, free content like this takes significant time and effort. Your support helps me continue sharing knowledge and creating more helpful resources for students like you.

☕ Buy me a coffee - Every contribution, big or small, means the world to me and keeps me motivated to create more content!


Cover image by Ries Bosch on Unsplash

Related Blogs

Ojaswi Athghara

SDE, 4+ Years

© ojaswiat.com 2025-2027