These two patterns let you solve problems in O(n) that most people brute-force in O(nยฒ). They share a core idea: maintain a smart window into the data instead of re-scanning it.
Place one pointer at each end of a sorted array. Move them inward based on a condition.
def two_sum_sorted(arr, target):
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 bigger sum
else:
right -= 1 # need smaller sum
return [-1, -1]
Key invariant: Everything to the left of L is too small. Everything to the right of R is too big. The answer must be between them.
| Problem | Trick | Complexity | |---------|-------|------------| | Two Sum (sorted) | Converge on target | O(n) | | Container with Most Water | Move the shorter wall inward | O(n) | | 3Sum | Fix one, two-pointer the rest | O(nยฒ) | | Remove Duplicates (sorted) | Slow/fast pointer | O(n) |
Maintain a window [left, right] that slides across the array. Expand right, shrink left โ never re-scan the window.
Fixed-size window (size k):
def max_sum_subarray(arr, k):
window_sum = sum(arr[:k])
max_sum = window_sum
for i in range(k, len(arr)):
window_sum += arr[i] - arr[i - k] # slide: add new, remove old
max_sum = max(max_sum, window_sum)
return max_sum
Variable-size window (expand/shrink):
def longest_substring_no_repeat(s):
seen = set()
left = max_len = 0
for right in range(len(s)):
while s[right] in seen:
seen.remove(s[left])
left += 1 # shrink window
seen.add(s[right])
max_len = max(max_len, right - left + 1)
return max_len
Why does the variable window still run in O(n)? Each element is added to the set once and removed at most once โ that's 2n operations total.
| Problem | Window Type | Key Insight | |---------|-------------|-------------| | Max sum subarray of size k | Fixed | Slide and track sum | | Longest substring without repeats | Variable | Expand right, shrink left on duplicate | | Minimum window substring | Variable | Shrink when all chars found | | Max consecutive ones (k flips) | Variable | Shrink when flips exceed k |
These aren't just interview patterns โ they're how production ML systems work:
| Pattern | When | Time | Space | |---------|------|------|-------| | Two Pointers (converge) | Sorted array, find pair | O(n) | O(1) | | Two Pointers (fast/slow) | Linked list cycle, partitioning | O(n) | O(1) | | Fixed Sliding Window | Subarray of exact size k | O(n) | O(1) | | Variable Sliding Window | Longest/shortest subarray with condition | O(n) | O(k) |