Phase 01 · Fundamentals

Arrays

The most fundamental data structure in computer science — a contiguous block of memory storing elements of the same type, accessible via index in O(1) time.

~15 min read
Beginner
Python · JavaScript · Java

Overview

An array is a collection of items stored at contiguous memory locations. The idea is to store multiple items of the same type together, making it easy to calculate the position of each element by simply adding an offset to a base value (the memory address of the first element).

Arrays are used extensively in algorithm problems and system design. Understanding their performance characteristics is essential for writing efficient code.

💡

Interview Insight

Arrays appear in roughly 40% of coding interview questions. Master two-pointer, sliding window, and prefix sum patterns before your interviews.

Time Complexity

OperationAverageWorstNotes
AccessO(1)O(1)Direct index lookup
SearchO(n)O(n)Linear scan required
Insert (end)O(1)O(n)Amortized — resize on overflow
Insert (middle)O(n)O(n)Elements must shift right
Delete (end)O(1)O(1)Just decrement size
Delete (middle)O(n)O(n)Elements must shift left

Space complexity: O(n) — proportional to the number of elements stored.

Core Patterns

Two Pointer

Use two pointers moving toward each other (or in the same direction) to reduce O(n²) solutions to O(n).

Python
# Check if array has a pair summing to target
def two_sum_sorted(arr: list, target: int) -> bool:
    left, right = 0, len(arr) - 1

    while left < right:
        current = arr[left] + arr[right]
        if current == target:
            return True
        elif current < target:
            left += 1   # need bigger sum
        else:
            right -= 1  # need smaller sum

    return False

# Time: O(n)  |  Space: O(1)

Sliding Window

Maintain a window of elements and slide it across the array to avoid recomputing from scratch on each step.

Python
# Maximum sum subarray of size k
def max_subarray_sum(arr: list, k: int) -> int:
    window_sum = sum(arr[:k])
    max_sum = window_sum

    for i in range(k, len(arr)):
        window_sum += arr[i] - arr[i - k]  # slide
        max_sum = max(max_sum, window_sum)

    return max_sum

# Time: O(n)  |  Space: O(1)

Prefix Sum

Precompute cumulative sums to answer range-sum queries in O(1) after O(n) preprocessing.

Python
# Build prefix sums, then query any range in O(1)
def build_prefix(arr: list) -> list:
    prefix = [0] * (len(arr) + 1)
    for i, v in enumerate(arr):
        prefix[i + 1] = prefix[i] + v
    return prefix

def range_sum(prefix: list, l: int, r: int) -> int:
    return prefix[r + 1] - prefix[l]  # O(1)

Common Interview Problems

  • Two Sum — find pair summing to target (use HashMap for O(n))
  • Best Time to Buy/Sell Stock — single pass, track min price seen so far
  • Maximum Subarray — Kadane's algorithm, O(n) dynamic programming
  • Rotate Array — reverse trick: O(n) time, O(1) space
  • Product of Array Except Self — left/right prefix products, no division
  • Container With Most Water — two-pointer, greedy shrink of wider side
  • Trapping Rain Water — two-pointer or prefix max arrays

Pattern Recognition Tip

When a problem asks for a contiguous subarray and mentions "maximum", "minimum", or "sum" — default to sliding window or Kadane's. When it asks for a "pair" or "triplet" — default to two-pointer on a sorted array.

Memory Layout

Arrays store elements in contiguous memory blocks. This enables cache-friendly access patterns — the CPU prefetcher can anticipate sequential reads, making array iteration significantly faster than linked lists in practice, even though both are theoretically O(n).

C — Memory layout
/* int arr[4] — stored at base address 0x1000 */
arr[0]  →  address 0x1000  (4 bytes)
arr[1]  →  address 0x1004  (4 bytes)
arr[2]  →  address 0x1008  (4 bytes)
arr[3]  →  address 0x100C  (4 bytes)

/* element address = base + (index × element_size) */
addr(arr[i]) = 0x1000 + i * sizeof(int)

Watch out: Off-by-One Errors

Array indices are 0-based in most languages. The last valid index is n - 1 not n. Out-of-bounds access is one of the most common bugs in array-related code.

Dynamic Arrays

Languages like Python (list) and Java (ArrayList) implement dynamic arrays that resize automatically. When capacity is exceeded, a new array of typically 2× the size is allocated and all elements are copied — this resize operation is O(n), but it happens infrequently enough that the amortized cost of append is O(1).

  • Python: list — dynamic, mixed types allowed via boxing
  • Java: ArrayList<T> — typed, backed by Object array
  • JavaScript: Array — sparse, dynamic, can hold any type
  • Go: slice — header (ptr, len, cap) over backing array