Core Concepts
Subsequence — elements in original relative order, not necessarily contiguous. A subarray is always a subsequence; the reverse is false. Partition — rearranging elements so all satisfying a predicate precede all that don't, without sorting.
Structural Invariants
| Property | Guarantee | What breaks if violated |
|---|---|---|
| Contiguous allocation | arr[i] and arr[i+1] are adjacent in memory | O(1) random access fails; cache locality collapses |
| Fixed capacity (static) | Writes beyond capacity overwrite other memory | Undefined behavior / index error |
| Length consistency | len(arr) always reflects the current live element count | Off-by-one errors; reading uninitialized slots |
Types / Variants
| Variant | Distinguishing property | When to prefer |
|---|---|---|
| Static array | Fixed length, no reallocation | Known size, cache-sensitive code |
| Dynamic array | Amortized O(1) append, arbitrary length | Default choice in interviews |
| Circular array | Modulo-indexed, O(1) front/back | Sliding window, deque simulation, BFS queue |
| 2D array / Matrix | Nested indexing; row-major layout | Grid, DP table, image problems |
| Jagged array | Rows of different lengths | Adjacency lists, triangular DP tables |
| Difference array | Derived; enables O(1) range updates | Many range add/subtract, then final query |
Traversals & Access Patterns
Two-pointer converging — l = 0, r = n-1; advance l or retreat r based on a condition. Requires sorted array or symmetric structure. Terminates when l >= r.
Two-pointer parallel (fast/slow) — both pointers move forward; fast skips elements the slow pointer should not see. Used for in-place filtering, remove-duplicates, partition.
Sliding window (variable size) — l and r both move forward only; shrink from left while a constraint is violated. Total pointer moves = O(n) because l never passes r and neither decrements.
Index jumping — i = arr[i] or i += arr[i]. Used for cycle detection (Floyd's), jump game reachability, cyclic sort.
Topic-Specific Operations
| Operation | Mechanism | Time |
|---|---|---|
| Swap | Tmp variable or XOR (ints only) | O(1) |
| Reverse in-place | Two-pointer swap from ends inward | O(n) |
| Rotate right by k | Reverse all → reverse first k → reverse rest | O(n), O(1) space |
| Partition | Dutch National Flag / two-pointer | O(n), O(1) space |
Key Algorithms
Kadane's Algorithm
Key insight: at each position, the best subarray ending here is either arr[i] alone (start fresh) or arr[i] added to the best subarray ending at i-1. Track overall max separately.
Dutch National Flag (Three-Way Partition)
Partitions an array into three groups (e.g., 0s, 1s, 2s) in O(n) time, O(1) space. Used for Sort Colors and any 3-value rearrangement.
Three pointers: lo (boundary of group 0), mid (current), hi (boundary of group 2). Swap arr[mid] based on its value; advance mid only when it lands in group 1.
Boyer-Moore Voting
Finds the majority element (appears > n/2 times) in O(n) time, O(1) space.
count = 0
for x in arr:
if count == 0: candidate = x
count += 1 if x == candidate else -1
Cyclic Sort
Key insight: arr[i] belongs at index arr[i] - 1; swap until arr[i] is at its correct position, then advance.
Quickselect
Finds the kth smallest element in O(n) average, O(n²) worst. Partitions around a pivot; recurse only into the relevant half.
Difference Array
For range add queries followed by a final read. D[l] += v, D[r+1] -= v applies the update in O(1). Reconstruct with prefix sum in O(n). O(n) total for q updates: O(n + q) vs O(nq) for naive.
Counting Sort / Frequency Map
When values are in a bounded range [0, k]. Count occurrences in O(n); reconstruct in O(n + k). Stable. Breaks when k >> n.
Advanced Techniques
Coordinate Compression
Solves: problems where values span a huge range (e.g., up to 10⁹) but there are only n distinct values; needed before applying array-indexed structures like BIT or segment tree. Mechanism: sort and deduplicate values, assign rank 0..m-1; replace each value with its rank. Queries and updates use ranks. When to prefer: value range >> n; otherwise just use values directly as indices. Complexity: O(n log n) for sorting.
Sparse Table (Range Minimum / Maximum Query)
Solves: static array range min/max in O(1) per query after O(n log n) preprocessing.
Mechanism: ST[i][j] = min of arr[i..i + 2^j - 1]. Any range [l, r] covered by two overlapping windows of size 2^k where k = floor(log2(r-l+1)).
When to prefer over prefix sum: when the operation is idempotent (min, max, gcd) so overlapping windows are valid; prefix sum handles sum/xor but not min/max.
Complexity: O(n log n) space and build, O(1) query. Not suitable for updates.
Offline Query Processing with Sorting
Solves: range queries that can be answered more efficiently if processed in a specific order (e.g., all queries on a fixed right boundary). Mechanism: sort queries by right endpoint; sweep a pointer across the array and answer queries as their right endpoint is reached. Often combined with a hash map or prefix structure. When to prefer over online processing: when queries are given upfront and no interleaving with updates; allows amortized O(n + q) solutions where online would need O(q log n). Complexity: O((n + q) log(n + q)) including sort.
Two-Pointer with Monotonic Invariant
Solves: "longest subarray where max - min ≤ k", "number of subarrays with property P" where P is monotone in window size. Mechanism: combine sliding window with a monotonic deque to track max and min simultaneously. Window shrinks when invariant breaks; deque evicts stale or dominated elements. When to prefer: the window condition involves both maximum and minimum simultaneously; simple sliding window without auxiliary structure cannot decide shrink/grow correctly. Complexity: O(n) with deque.
Problem Taxonomy
By Problem Category
| Category | What it asks | Key technique |
|---|---|---|
| Pair / triplet with target | Two or more elements summing to target | Hash map (unsorted); two pointers (sorted) |
| Rearrangement / partition | Sort by condition, move category to a region | Dutch National Flag; two-pointer partition |
| Find missing / duplicate | Element(s) outside expected frequency | XOR trick; cyclic sort; hash set |
| Rotation / shift | Circular indexing, rotated structure | Reverse trick; modulo indexing |
| Sliding window (fixed k) | Property of every contiguous window of size k | Add/subtract window edges |
| Sliding window (variable) | Longest/shortest subarray satisfying a constraint | Shrinkable window with invariant |
| Search in sorted / rotated | Find target, kth element, boundary | Binary search variants |
| Matrix traversal | Spiral, diagonal, layer-by-layer | Boundary pointers; index formulas |
| Interval / merge | Overlapping intervals, coverage | Sort by start; greedy merge |
| Counting / frequency | How many subarrays / elements satisfy condition | Prefix sum + hash map; sliding window |
Problem Signal → Technique
| Signal in problem statement | Likely technique |
|---|---|
| "maximum sum subarray" | Kadane's |
| "subarray sum equals k" | Prefix sum + hash map (store count of each prefix sum) |
| "product of array except self" | Prefix product left + suffix product right |
| "pair / two numbers sum to target", sorted | Two pointers converging |
| "pair / two numbers sum to target", unsorted | Hash map complement |
| "k-th largest / smallest" | Quickselect or min-heap of size k |
| "majority element" (> n/2) | Boyer-Moore voting |
| "majority element" (> n/3) | Boyer-Moore with two candidates |
| "move all zeros to end" | Two-pointer fast/slow partition |
| "sort colors" / 3-way partition | Dutch National Flag |
| "contains duplicate" | Hash set |
| "find duplicate in [1, n]" | XOR or cyclic sort or Floyd's cycle |
| "first missing positive" | Cyclic sort; in-place negation |
| "range sum, no updates" | Prefix sum |
| "range add, then read" | Difference array |
| "rotate array by k" | Triple reverse |
| "fixed window of size k" | Sliding window add/remove |
| "longest subarray with ≤ k distinct" | Variable sliding window + frequency map |
| "search in rotated sorted array" | Binary search with pivot check |
| "minimum in rotated sorted array" | Binary search on inflection point |
| "next greater element" | Monotonic stack (see stacks.md) |
| "trapping rain water" | Prefix max + suffix max; two pointers |
| "container with most water" | Two pointers converging, keep larger side |
| "all subarrays / count subarrays" | Prefix sum + hash map; contribution technique |
Common Patterns
| Pattern | When it applies | Mechanism |
|---|---|---|
| Hash map for complement | Find pair with target sum in O(n) | Store target - arr[i]; check if current element is already a stored complement |
| Sort first, then two-pointer | Pair/triplet sum; median; kth element | Sort once O(n log n); subsequent passes are O(n) |
| Prefix sum + hash map | Count subarrays with sum/XOR equal to k | Store count[prefix]; each new prefix queries the map |
| In-place negation as visited marker | Mark seen indices without extra space | Negate arr[abs(arr[i]) - 1]; negative = seen |
| Cyclic replacement for rotation | Rotate array or matrix in O(n), O(1) | Follow the permutation cycle; track how many elements placed |
| Triple reverse for right rotation | Rotate right by k in O(n), O(1) | Reverse all → reverse [0..k-1] → reverse [k..n-1] |
| Shrinkable sliding window | Longest/shortest window with a constraint | Advance right always; advance left only when constraint violated |
| Contribution counting | Sum over all subarrays / pairs | Count how many subarrays each element is the max/min/sum contributor to |
| Two-pass left/right | Product except self, trapping rain water | First pass accumulates from left; second from right; combine |
| Frequency array as hash map | Values bounded by small k | count = [0] * (k+1); O(1) access, O(k) space |
Edge Cases & Pitfalls
-
Single element: two-pointer loops with
l < rorl != rskip the element; sliding window of size 1 must still execute once. -
All identical values: two-pointer deduplication (3Sum) must skip duplicate values at both pointers after placing a candidate; otherwise produces duplicate triplets.
-
Two-pointer termination: use
l < r(notl <= r) for converging pointers to avoid processing the same element twice; usel <= rin binary search where single-element windows are valid. -
Off-by-one in window slide: when sliding a fixed window from position
itoi+1, remove element ati - k(noti - k + 1); draw a concrete example with k=3. -
Modifying array during iteration: backward scan
range(n-1, -1, -1)is safe for in-place removal; forward scan shifts indices and causes elements to be skipped. -
Integer overflow: Python has arbitrary precision, so
sum(arr)never overflows; in Java/C++, uselongfor sums ofintarrays. -
Midpoint overflow (Java/C++):
mid = l + (r - l) // 2, not(l + r) // 2, to avoid overflow whenl + r > MAX_INT. -
Python
[[val] * cols] * rowstrap: creates one list shared across all rows; mutations to one row affect all. Use[[val] * cols for _ in range(rows)]. -
Binary search on rotated array: must determine which half is sorted before deciding which side to search; checking
arr[l] <= arr[mid](not<) handles the case wherel == mid.
Implementation Notes
arr[l:r]creates a copy — O(r-l) time and space. In tight loops, tracklandras indices instead.arr[-1]is the last element;arr[-k:]is the last k elements. Useful but can obscure bugs ifkis accidentally 0 (returns empty, not full array).collections.Counter(arr)builds a frequency map in O(n);.most_common(k)returns top k in O(n log k).enumerate(arr)gives(index, value)pairs; prefer it overrange(len(arr))for readability.bisect.bisect_left(arr, x)returns the leftmost position to insertxkeepingarrsorted (lower bound).bisect_rightreturns rightmost (upper bound). Both are O(log n).zip(arr, arr[1:])iterates consecutive pairs without index arithmetic.
Cross-Topic Relations
| Related topic | Specific connection |
|---|---|
| Stack / Monotonic Stack | Stack algorithms (next greater element, histogram) operate over arrays; result stored back in arrays |
| Segment Tree / BIT | Advanced range query on arrays; use when prefix sum is insufficient (dynamic updates needed) |
| Heap | Array-backed; heap algorithms (top-k, kth largest) are applied to array inputs |
| Dynamic Programming | Most DP tables are arrays or 2D arrays; array traversal order determines DP update correctness |
Interview Reference
Must-Know Problems
Subarray / Kadane's
- Maximum Subarray (LC 53) — Kadane's baseline
- Maximum Product Subarray (LC 152) — track both max and min (negative × negative)
- Subarray Sum Equals K (LC 560) — prefix sum + hash map
- Minimum Size Subarray Sum (LC 209) — variable sliding window
Prefix Sum / Range
- Subarray Sum Divisible by K (LC 974) — prefix sum mod k
Two Pointers / Pair Sum
- Two Sum II - Input Array Is Sorted (LC 167) — converging two pointers
- 3Sum (LC 15) — sort + converging two pointers with dedup
- Container With Most Water (LC 11) — shrink the shorter side
- Trapping Rain Water (LC 42) — two-pass or two-pointer
Partition / Rearrangement
- Sort Colors (LC 75) — Dutch National Flag
- Move Zeroes (LC 283) — fast/slow two-pointer
- Rotate Array (LC 189) — triple reverse
Missing / Duplicate
- Find the Duplicate Number (LC 287) — Floyd's cycle or binary search
- First Missing Positive (LC 41) — cyclic sort / in-place negation
- Find All Numbers Disappeared in Array (LC 448) — in-place negation
Search in Sorted / Rotated
- Find Minimum in Rotated Sorted Array (LC 153) — binary search for the unsorted half boundary
- Search in Rotated Sorted Array (LC 33) — binary search; identify the sorted half each step
- Find First and Last Position (LC 34) — lower/upper bound binary search
Matrix
- Spiral Matrix (LC 54) — boundary pointer shrink
- Rotate Image (LC 48) — transpose then reverse rows
- Set Matrix Zeroes (LC 73) — use first row/col as markers
Hard / Synthesis
- Median of Two Sorted Arrays (LC 4) — binary search on partition
- Largest Rectangle in Histogram (LC 84) — monotonic stack over array
Additional LeetCode Coverage
- Summary Ranges (LC 228) — scan consecutive runs and emit start/end
- Find Pivot Index (LC 724) — prefix sum; left sum equals total minus left minus current
- Monotonic Array (LC 896) — track whether any increasing/decreasing violation occurs
- Valid Mountain Array (LC 941) — climb strictly up, then strictly down; both sides required
- Replace Elements with Greatest Element on Right Side (LC 1299) — scan from right with running maximum
- Minimum Value to Get Positive Step by Step Sum (LC 1413) — track minimum prefix sum; start must offset it to at least 1
- Kids With the Greatest Number of Candies (LC 1431) — compare each value plus extra candies against global max
- Find the Highest Altitude (LC 1732) — prefix sum over gains; track maximum altitude
- Check if Array Is Sorted and Rotated (LC 1752) — count drops; at most one rotation break is allowed
Common Interview Mistakes
- Initialising Kadane's
best = 0— fails when all elements are negative; must initialise toarr[0]. - Forgetting to skip duplicates in 3Sum after fixing the outer element and after advancing the two pointers — produces duplicate triplets.
- Using
l <= rtermination for converging two pointers — processes the same element twice; usel < r. - Declaring O(n) extra space when the problem says in-place — re-read the constraint before coding.
- Building prefix sum with 0-based indexing and querying with off-by-one:
P[r] - P[l-1]requires a guard forl = 0; the 1-indexed sentinelP[0] = 0eliminates this. - Confusing "subarray" and "subsequence" — wrong solution category entirely.
- Misidentifying which half of a rotated sorted array is sorted — must check
arr[l] <= arr[mid]and handle the equals case. - Not handling the empty-matrix case before accessing
matrix[0]— runtime crash in Python.
Typical Follow-Up Escalations
| Follow-up prompt | Expected direction |
|---|---|
| "Now do it in O(1) space" | In-place two-pointer, reverse trick, or math (XOR, negation as marker) |
| "Now support range updates, not just queries" | Prefix sum → difference array (add) or Fenwick tree / segment tree |
| "Now the array is modified between queries" | Static prefix sum → BIT or segment tree |
| "Now it's a 2D matrix" | Extend the 1D technique row-by-row; use 2D prefix sum for range queries |
| "Now find all such subarrays, not just one" | Count via hash map on prefix sums; contribution technique |
Read Next
Start reading to get personalized recommendations
Explore Unread
Great job! You've read all available articles