Why This Matters
You already know how to use arrays -- push, pop, map, filter. But in technical interviews and production code, the basic operations are not enough. You need patterns -- reusable strategies for solving entire categories of problems efficiently.
The two-pointer technique and sliding window pattern are two of the most powerful tools in algorithm design. They turn naive O(n^2) brute-force solutions into elegant O(n) algorithms. Once you learn these patterns, you will recognize them everywhere: in search algorithms, string processing, data streaming, and interview questions.
Understanding how dynamic arrays work under the hood also helps you make better performance decisions -- knowing when operations are O(1) versus O(n) can prevent subtle production bottlenecks.
Define Terms
Visual Model
The full process at a glance. Click Start tour to walk through each step.
Two pointers move inward from both ends, narrowing the search space with each step.
Code Example
// TWO-POINTER: Find pair with target sum in sorted array
function twoSum(sorted, target) {
let left = 0;
let right = sorted.length - 1;
while (left < right) {
const sum = sorted[left] + sorted[right];
if (sum === target) return [sorted[left], sorted[right]];
if (sum < target) left++; // need larger sum
else right--; // need smaller sum
}
return null;
}
console.log(twoSum([1, 3, 5, 7, 9, 11, 14], 14)); // [3, 11]
// SLIDING WINDOW: Maximum sum of k consecutive elements
function maxSubarraySum(arr, k) {
if (arr.length < k) return null;
// Calculate sum of first window
let windowSum = 0;
for (let i = 0; i < k; i++) {
windowSum += arr[i];
}
let maxSum = windowSum;
// Slide the window: add next, remove first
for (let i = k; i < arr.length; i++) {
windowSum += arr[i] - arr[i - k];
maxSum = Math.max(maxSum, windowSum);
}
return maxSum;
}
console.log(maxSubarraySum([2, 1, 5, 1, 3, 2], 3)); // 9 (5+1+3)
// DYNAMIC ARRAY: How push works under the hood
// Arrays double capacity when full
const arr = [];
for (let i = 0; i < 8; i++) {
arr.push(i); // Usually O(1), occasionally O(n) when resizing
}
console.log(arr); // [0, 1, 2, 3, 4, 5, 6, 7]
// PREFIX SUM: precompute sums for O(1) range queries
function buildPrefixSum(arr) {
const prefix = [0];
for (let i = 0; i < arr.length; i++) {
prefix.push(prefix[i] + arr[i]);
}
return prefix;
}
function rangeSum(prefix, left, right) {
return prefix[right + 1] - prefix[left];
}
const prefix = buildPrefixSum([3, 1, 4, 1, 5]);
console.log(rangeSum(prefix, 1, 3)); // 6 (1+4+1)Interactive Experiment
Try these exercises:
- Modify the two-pointer
twoSumfunction to return the indices instead of the values. - Use the sliding window pattern to find the smallest subarray whose sum is greater than or equal to a given target.
- Write a function that rotates an array by k positions to the right using O(1) extra space. Hint: reverse three times.
- Build a prefix sum array and use it to answer 5 different range sum queries. Compare this to computing each sum from scratch with a loop.
Quick Quiz
Coding Challenge
Write a function `pairSum` that takes a SORTED array of integers and a target sum. Return the indices (as a two-element array) of the two numbers that add up to the target. Use the two-pointer technique for O(n) time and O(1) space. If no pair exists, return [-1, -1].
Real-World Usage
These array patterns appear throughout production software:
- Merge operations: Git's merge algorithm uses a two-pointer approach to walk through two sorted commit histories simultaneously.
- Network monitoring: Sliding window protocols (like TCP) track which packets have been sent and acknowledged using a window that slides forward over time.
- Data streaming: Analytics systems compute running averages, max values, and anomaly detection over sliding windows of time-series data.
- Search results: Merging results from multiple sorted indexes (like Elasticsearch shards) uses multi-pointer merging.
- Memory allocators: Dynamic arrays and amortized resizing are how JavaScript arrays, Python lists, and Java ArrayLists work internally.