Array scanning patterns — turning a nested loop into a single pass
This chapter organizes four patterns for reducing nested loops to a single pass by applicability. It covers two-pointer, sliding window (fixed and variable), prefix sum for range totals, monotonic stack for "next greater element", and the decision procedure for picking the right one.
Binary search — halving a sorted array
This chapter explains binary search from the invariant of halving the search range each round. It covers implementation pitfalls (midpoint calculation, boundary conditions, non-shrinking ranges), time and space complexity, why iteration and recursion differ in space, and the conditions under which it applies.
Bit operations — holding flags in bits
This chapter explains bitwise operators (AND, OR, XOR, NOT, shift) and the implementation of bit flags — packing several booleans into a single integer. It covers testing, adding, removing, and toggling flags, building masks, and the point that JavaScript's bitwise operators run on 32-bit signed integers.
Choosing data structures — arrays, lists, stacks, hashes, and trees
This chapter compares arrays, linked lists, stacks, queues, hash maps, trees, and tries by operation complexity. It covers that stacks are LIFO and queues are FIFO, why hash maps average O(1) and what the worst case is, and why tries excel at prefix matching.
Complexity — sizing speed and memory with big-O
This chapter explains big-O by starting from the idea of dropping constant factors and lower-order terms. It covers the feel of common orders, the difference between time and space complexity, how to count orders from loops and recursion, and when to use worst, average, and best cases.
Dynamic programming — never doing the same work twice
This chapter starts from noticing subproblem overlap and derives dynamic programming. It covers the correspondence between memoization and tabulation, the two conditions for applicability, estimating complexity as state count × transition cost, space compression by keeping only the previous row, and the difference from greedy.
Graphs and traversal — following the connections
This chapter introduces graph vocabulary and two representations, then explains when to use breadth-first vs. depth-first search. It covers why BFS produces shortest paths without weights, why visited sets are needed, ordering by dependency and detecting cycles with topological sort, and the trick of treating states as vertices.
Recursion and divide-and-conquer — throwing a large problem back at a smaller self
This chapter explains how to design recursion by splitting into a base case and a recursive step. It covers counting work with a recursion tree, that the call stack consumes space, merge sort vs. quicksort as divide-and-conquer, when stable sort is required, and choosing between recursion and iteration.