Home/SWE Hub/Arrays, Two Pointers & Sliding Window
Back
๐ŸชŸ

Algorithms

Arrays, Two Pointers & Sliding Window

Arrays are the foundation of nearly every coding interview. Mastering two-pointer techniques and sliding window patterns lets you solve O(nยฒ) brute-force problems in O(n) time. These patterns appear in 30-40% of all FAANG coding questions โ€” they are non-negotiable.

Basic array indexingPython/Java syntaxBig-O notationTwo PointersSliding WindowPrefix SumSubarrayIn-PlaceKadane's Algorithm

Core Concepts

  • 1Two pointer technique โ€” convergent: place one pointer at the start, one at the end. Move them toward each other based on a condition. Classic use case: finding a pair that sums to a target in a sorted array. Instead of O(nยฒ) nested loops, you move left pointer right when sum is too small, right pointer left when sum is too large โ€” O(n) total. The key insight: because the array is sorted, you have perfect information about which direction to move each pointer. Works for: two-sum in sorted array, three-sum (fix one, two-pointer the rest), container with most water, trapping rain water.
  • 2Two pointer technique โ€” fast/slow (Floyd's algorithm): one pointer moves one step at a time, the other moves two. If there's a cycle, they will meet inside it. Used to detect cycles in linked lists, find the middle of a linked list (stop when fast reaches end), and detect duplicate numbers in arrays. For finding the middle: when fast reaches the end, slow is at the middle โ€” useful for merge sort and palindrome checking.
  • 3Sliding window โ€” fixed size: maintain a window of exactly k elements. To slide: add the new right element, subtract the old left element. Example: maximum sum subarray of size k โ€” compute the sum of the first k elements, then slide right and update in O(1) per step. Total O(n). Template: initialize window sum for first k elements; for i from k to n: sum += arr[i] - arr[i-k]; update result.
  • 4Sliding window โ€” variable size: expand right pointer until the window is invalid; shrink from the left until valid again. Example: smallest subarray with sum โ‰ฅ target. Right pointer always moves forward (n times total). Left pointer also only moves forward (n times total). Total O(n) โ€” not O(nยฒ) even though there's a nested while loop, because each pointer traverses the array at most once. Template: left=0, result=inf; for right in range(n): add arr[right]; while window invalid: subtract arr[left], left++; update result.
  • 5Prefix sums: precompute prefix[i] = arr[0] + arr[1] + ... + arr[i-1]. Then sum(arr[l..r]) = prefix[r+1] - prefix[l] in O(1). Build prefix in O(n), answer each range sum query in O(1). Extension: 2D prefix sums for matrix region sum queries. Critical use case: subarray sum equals k โ€” for each right index, check how many left indices have prefix[right] - prefix[left] = k, equivalently prefix[right] - k has been seen before. Use a hashmap of {prefix_sum: count}.
  • 6Kadane's algorithm for maximum subarray: the key insight is: the maximum subarray ending at index i either (a) extends the maximum subarray ending at i-1, or (b) starts fresh at i. So: current_max = max(arr[i], current_max + arr[i]). Global max = max over all i of current_max. O(n) time, O(1) space. Handles negative numbers correctly. Variation: maximum product subarray requires tracking both max and min (because negative ร— negative = positive).
  • 7In-place array manipulation: many problems ask you to modify an array without extra space. Common techniques: (1) Use the array values as indices to mark visited positions (negation trick): if arr[abs(arr[i])-1] > 0, negate it to mark that value i was seen. (2) Two pointers for removing duplicates: keep a 'write pointer' that only advances when a new unique element is found. (3) Dutch National Flag (3-way partition): three pointers for values 0, 1, 2 โ€” sort in a single pass. (4) Rotation: reverse subarrays โ€” reverse whole array, reverse first k, reverse last n-k.

Key Patterns & Templates

Two pointers (sorted array): left=0, right=n-1; while left<right: check condition, move left++ or right--
Sliding window (fixed k): sum of first k; for i in range(k,n): sum += a[i]-a[i-k]; update ans
Sliding window (variable): left=0; for right in range(n): add a[right]; while invalid: remove a[left++]; update ans
Prefix sum: pre[0]=0; pre[i]=pre[i-1]+a[i-1]; range sum = pre[r+1]-pre[l]
Subarray sum = k: use hashmap {prefix_sum โ†’ count}; ans += map[prefix[i]-k]
Kadane's: cur=a[0]; ans=a[0]; for x in a[1:]: cur=max(x,cur+x); ans=max(ans,cur)

Worked Examples

Given strings s and t, return the minimum window in s that contains all characters of t. Return '' if no window exists.

1Step 1 โ€” Brute force: O(nยฒm). Try all O(nยฒ) windows, check each in O(m). Immediately propose the sliding window approach.
2Step 2 โ€” Key insight: we need a way to know when a window is 'valid' (contains all chars of t) and to shrink it efficiently. Use a frequency counter for t and track 'missing' = number of chars still needed.
3Step 3 โ€” Expand right: for each character at right, if need[c] > 0, it means we actually needed it โ€” decrement missing. Always decrement need[c] (it can go negative, meaning we have extras).
4Step 4 โ€” Shrink left when missing == 0: while need[s[left]] < 0 (we have extra of this char), increment need[s[left]] and advance left. Now s[left..right] is the minimum valid window ending at right.
5Step 5 โ€” Record and advance: save this window if it's the best. To search for the next window: 'release' s[left] by incrementing need[s[left]] and missing, then advance left.
6Step 6 โ€” Complexity: right pointer moves n times total, left pointer moves at most n times total โ€” O(n+m). Space O(|charset|).
โœ“ Time O(n+m), Space O(|charset|). The 'need' counter going negative is the key trick โ€” it lets you know when a character in the window is extra (negative) vs. required (positive) without a separate data structure.

Common Mistakes

โš 

Off-by-one in window size: for a fixed window of size k, the window [i-k+1, i] starts being valid when i >= k-1. Write 'if i >= k-1: record result' not 'if i >= k'. Test with k=1 (every element is a valid window of size 1).

โš 

Forgetting to skip duplicates in 3Sum: after finding a valid triplet, advance both pointers AND skip duplicates. 'while left < right and nums[left] == nums[left+1]: left += 1' THEN 'left += 1'. Same for right. Otherwise you get duplicate triplets in output.

โš 

Not initializing the prefix sum hashmap with {0: 1}: for subarray sum problems, prefix[0] = 0 represents the empty subarray. Without this initialization, you miss subarrays that start from index 0. Classic bug: 'why is my answer off by the count of subarrays starting at 0?'

โš 

Dutch National Flag: not incrementing mid when swapping with hi: after swapping nums[mid] with nums[hi], decrement hi but DO NOT increment mid โ€” the newly swapped value at nums[mid] hasn't been examined yet. This is the most common bug in the 3-way partition.

โš 

Treating the variable sliding window while-loop as O(nยฒ): beginners see a while loop inside a for loop and assume O(nยฒ). The correct analysis: left and right each traverse the array exactly once โ€” right from 0 to n-1 (n steps), left from 0 to at most n-1 (at most n total steps). Total 2n = O(n). This amortized analysis is important to explain in interviews.

Only works in the Electron app

<webview> is an Electron-only tag. Run npm run electron:dev to use this.

25:00Focus
0

25 min focus ยท 5 min break ยท long break every 4 sessions

The Ultimate Grind