Search, traverse, partition, relax. Each algorithm runs in your browser with the same controls - play, step, scrub, replay - so the trick stops being a trick and starts being a pattern you recognize.
New to this section? Work through these in order - each builds on the previous.
Explore the graph layer by layer from the start node, using a queue to defer further nodes. Every node is enqueued at most once because we mark it visited the moment it's enqueued. The resulting BFS tree gives the shortest path (in edges) from the start to every reachable node.
Dive as deep as possible along each branch before backtracking. Implemented with recursion (or an explicit stack), DFS records two timestamps per node - a discovery time when it's first entered and a finish time when its recursion returns. These timestamps are the foundation of topological sort, cycle detection, and strongly-connected components.
From the source outward, always finalize the closest unfinalized node next. When we finalize u, we relax every edge out of u: if going through u beats v's current best, we update v's distance. A priority queue keyed by tentative distance gives us 'next-closest' in O(log n). The greedy choice works because edge weights are non-negative - once you finalize a node, no later relaxation could ever improve it.
Order the nodes of a DAG so every edge points forward. Kahn's algorithm: compute the in-degree of every node, start a queue with all the 0-in-degree nodes (nothing has to happen before them), then repeatedly pop a node, append it to the output, and decrement the in-degree of its neighbors - pushing any whose in-degree just hit 0. If you finish with fewer nodes than the graph has, the leftovers form a cycle. Build systems, course prerequisites, and task scheduling all reduce to this.
Instead of re-summing each window from scratch in O(k), maintain a running sum. When the window slides one step right, add the new incoming element and subtract the outgoing one - an O(1) update per slide. The whole algorithm is O(n), independent of the window size.
Two indices that scan an array together instead of one. The two canonical shapes: 'opposite ends' (start at 0 and n−1; move inward based on a comparison) is how you find pairs with a target sum on a sorted array in O(n). 'Fast/slow' (one index for reading, one for writing) is how you do in-place dedup or move-zeroes in O(n). Both replace what would otherwise be an O(n²) brute force with a single pass.
Sort by *dividing* the array in half, sorting each half recursively, then *merging* the two sorted halves into one sorted output. The merge step is the engine: walk two pointers through the halves, repeatedly pick the smaller front element, and copy it to the output. Each element is touched O(log n) times across the recursion and O(1) per level on the merge - net O(n log n) total. Unlike quick sort the runtime is *guaranteed* - no adversarial input degrades it. The price is O(n) auxiliary space for the merge buffer.
Quick Sort sorts by partitioning. Pick a pivot (we take the last element - the Lomuto scheme), then sweep one pointer through the range pushing every value <= pivot to the left side. After the sweep the pivot lands at the boundary - everything left of it is <= pivot, everything right is > pivot - and the pivot is in its final sorted position. Recurse on both halves. Each level of recursion places one pivot, so n levels of pivots sort everything. Worst case is O(n²) on already-sorted input with a tail pivot; average is O(n log n).