Arrays
Think of it like this
Imagine a row of numbered mailboxes in an apartment building. Mailbox 0 is first, mailbox 1 is next, and so on. To grab mail from box 4, you go directly to box 4, you don't check boxes 0, 1, 2, 3 first. That direct access is what makes arrays powerful.
In memory, an array is exactly this: a contiguous block where each slot sits right next to the previous one. The CPU can jump to any element in one step using the formula:
address of element[i] = base_address + i × element_sizeMemory Layout
Index: 0 1 2 3 4 5
Value: [ 12 ][ 37 ][ 55 ][ 8 ][ 91 ][ 43 ]
Addr: 1000 1004 1008 1012 1016 1020
↑
base address
(each int = 4 bytes, so step = 4)Because elements are packed together, your CPU's cache loads nearby elements automatically. This cache locality makes array traversal blazingly fast in practice, even faster than the O(n) notation suggests.
Static vs Dynamic Arrays
| Static | Dynamic (e.g. JS Array, Python list) | |
|---|---|---|
| Size | Fixed at creation | Grows automatically |
| Insert at end | Must check capacity | Amortized O(1) |
| Memory | Exact | Pre-allocates extra (usually 2×) |
| Language | C, C++ int arr[10] | JavaScript, Python, Java ArrayList |
When a dynamic array runs out of space, it allocates a new block (typically 2× the old size) and copies everything. This copy costs O(n) but happens rarely, so the average cost per insertion is O(1), this is called amortized analysis.
Time Complexity
| Operation | Best | Average | Worst | Why |
|---|---|---|---|---|
Access arr[i] | O(1) | O(1) | O(1) | Direct address calculation |
| Search (unsorted) | O(1) | O(n) | O(n) | May need to scan all elements |
| Search (sorted, binary) | O(1) | O(log n) | O(log n) | Halves search space each step |
| Insert at end | O(1) | O(1)* | O(n)* | *Amortized; resize is rare |
| Insert at index i | O(1) | O(n) | O(n) | Must shift elements right |
| Delete at index i | O(1) | O(n) | O(n) | Must shift elements left |
Space Complexity
- Static: O(n), exactly n elements
- Dynamic: O(n) amortized, at most 2n slots allocated at any time
Real-World Frontend Application
Arrays power almost every list-based UI you build:
- React lists:
items.map(item => <Item key={item.id} />)iterates an array in O(n) - Virtual DOM diffing: React's reconciler compares two arrays of children (old vs new) to find which nodes changed
- Redux normalized state: entities stored as arrays with separate id-lookup maps
- Canvas pixel manipulation:
ImageData.datais a flat Uint8ClampedArray of RGBA values, a huge 1D array representing a 2D image
Core Patterns to Master
Pattern 1, Two Pointers (Opposite Ends)
Start one pointer at the left, one at the right. Move them toward each other based on a condition. Eliminates the need for nested loops in many problems.
Sorted array: [-2, 1, 3, 5, 8, 11]
↑L ↑R
Target sum = 9
Step 1: L(-2) + R(11) = 9 ✓ → Found!// Two Sum on a sorted array, O(n) instead of O(n²)
function twoSum(arr, target) {
let left = 0, right = arr.length - 1;
while (left < right) {
const sum = arr[left] + arr[right];
if (sum === target) return [left, right];
if (sum < target) left++; // need bigger sum
else right--; // need smaller sum
}
return [-1, -1];
}Two Pointers (Sorted Two Sum)
Target = 9. Start with left pointer at 0 and right pointer at len-1.
Pattern 2, Sliding Window (Fixed Size)
Keep a window of size k. Slide it one step at a time by adding the new element on the right and removing the old one on the left. Processes each element exactly once → O(n).
arr = [2, 1, 5, 1, 3, 2], k = 3
window: [2,1,5]→sum=8 max so far = 8
[1,5,1]→sum=7 max so far = 8
[5,1,3]→sum=9 max so far = 9
[1,3,2]→sum=6 max so far = 9
Answer: 9function maxSumWindow(arr, k) {
let windowSum = arr.slice(0, k).reduce((a, b) => a + b, 0);
let maxSum = windowSum;
for (let i = k; i < arr.length; i++) {
windowSum += arr[i] - arr[i - k]; // add new, remove old
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}Pattern 3, Prefix Sums
Precompute cumulative sums once in O(n), then answer any range-sum query in O(1).
arr = [ 3, 1, 4, 1, 5, 9, 2]
prefix = [ 3, 4, 8, 9, 14, 23, 25]
index: 0 1 2 3 4 5 6
Sum of arr[2..5] = prefix[5] - prefix[1] = 23 - 4 = 19
✓ (4 + 1 + 5 + 9 = 19)function buildPrefix(arr) {
const prefix = [0]; // prefix[0] = 0 (sentinel makes range queries cleaner)
for (const x of arr) prefix.push(prefix[prefix.length - 1] + x);
return prefix;
}
function rangeSum(prefix, l, r) {
return prefix[r + 1] - prefix[l]; // sum of arr[l..r] inclusive
}Pattern 4, Kadane's Algorithm (Maximum Subarray)
At each index, decide: extend the current subarray, or start fresh from here?
arr = [-2, 1, -3, 4, -1, 2, 1, -5, 4]
At each position, curMax = max(arr[i], curMax + arr[i])
curMax: -2 1 -2 4 3 5 6 1 5
maxSoFar: -2 1 1 4 4 5 6 6 6
Answer: 6 (subarray [4, -1, 2, 1])function maxSubarray(nums) {
let curMax = nums[0], maxSoFar = nums[0];
for (let i = 1; i < nums.length; i++) {
curMax = Math.max(nums[i], curMax + nums[i]);
maxSoFar = Math.max(maxSoFar, curMax);
}
return maxSoFar;
}Common Mistakes Beginners Make
| Mistake | Example | Fix |
|---|---|---|
| Off-by-one in loops | for i <= arr.length causes RangeError | Use i < arr.length |
| Mutating while iterating | arr.splice(i, 1) inside forEach | Collect indices, delete after |
| Forgetting array is passed by reference | Modifying inside a function affects the caller | Spread [...arr] to clone |
| O(n²) when O(n) is possible | Two nested loops for "any pair" | Use a hash set or two pointers |
Interview Checklist
Before coding, ask yourself:
- Is the array sorted? (enables binary search and two pointers)
- Can I use a hash map to trade space for time?
- Is a prefix sum useful? (any range query)
- Can a sliding window help? (contiguous subarray constraint)
- Do I need O(1) space? (can't use extra data structures)
Key Problems to Solve
| # | Problem | Pattern | Difficulty |
|---|---|---|---|
| 1 | Two Sum | Hash map | Easy |
| 2 | Best Time to Buy and Sell Stock | Single pass, min-so-far | Easy |
| 3 | Contains Duplicate | Hash set | Easy |
| 4 | Maximum Subarray (Kadane's) | DP / single pass | Medium |
| 5 | Product of Array Except Self | Prefix + suffix product | Medium |
| 6 | 3Sum | Sort + two pointers | Medium |
| 7 | Container With Most Water | Two pointers | Medium |
| 8 | Subarray Sum Equals K | Prefix sum + hash | Medium |
| 9 | Trapping Rain Water | Two pointers / prefix max | Hard |
| 10 | Sliding Window Maximum | Monotonic deque | Hard |
| 11 | Median of Two Sorted Arrays | Binary search on arrays | Hard |
