Advanced
advanced
Foundations
Amortized Analysis
Appending to a Python list or JavaScript array almost always feels instantaneous, yet every so often the structure allocates a fresh buffer and copies every element into it, an `O(n)` operation. So why do textbooks still call append `O(1)`? Because amortized over a long sequence of appends, the rare expensive operation is paid for by many cheap ones. **Amortized Analysis** is the formal machinery that makes this kind of argument rigorous. This lesson teaches the three classical methods. The **aggregate method** sums the total cost of `n` operations and divides by `n` for a per-operation bound. The **accounting (banker's) method** charges each operation a fixed amount and stores credits on the data structure to pay for future expensive ones. The **potential (physicist's) method** defines a potential function `Phi` and computes amortized cost as actual cost plus the change in `Phi`. You will apply all three to dynamic array doubling, stacks with multipop, and binary counters, and see how amortized `O(1)` differs from worst-case `O(1)` and from average-case analysis. This lesson stands on the shoulders of **Big-O Notation (Upper Bound)** and **Time Complexity Analysis Techniques**. From those lessons you can already analyze a single operation; amortized analysis is what you reach for when the cost of *one* operation is misleading and the right object of study is a *sequence* of operations. Next you will move to **Recurrence Relations**, the other major analysis tool, used when an algorithm's cost is most naturally written recursively rather than as a running total.
Not Started
0%
Basic Proof Techniques
Goldbach's conjecture has been verified for every even integer up to 4 * 10^18, yet mathematicians still call it a conjecture because no amount of testing covers every case. Algorithm correctness has the same shape: a function can pass a hundred unit tests and still fail on the empty list or the input size your tests never reached. **Basic Proof Techniques** equips you with the small set of argument styles that turn intuition into certainty about correctness, complexity bounds, and data structure invariants. Direct proof chains definitions and prior facts to a claim. Proof by contradiction assumes the opposite and derives a logical impossibility, as in the irrationality of `sqrt(2)` and the `Omega(n log n)` lower bound for comparison sorts. Mathematical induction, in weak and strong forms, proves statements over the natural numbers via a base case and an inductive step, the backbone of recurrence solutions and loop invariants. Proof by contraposition swaps `P implies Q` for the equivalent `not Q implies not P`, and proof by cases breaks a claim into exhaustive subcases. This lesson builds on **Discrete Mathematics Basics**, where you met sets, propositional logic, implications, and the first taste of formal proof. Here those informal sketches become the disciplined patterns that algorithm analysis, theoretical CS, and clean engineering arguments all rely on. With proofs in hand, you have completed the foundations track and are ready to step into **Arrays & Strings** and the rest of the data structures curriculum, armed to analyze every operation rigorously.
Not Started
0%
Complexity Classes (Conceptual Overview)
Some problems have algorithms that finish in seconds on inputs of size a million. Others, like finding the shortest tour through 30 cities, can defeat the world's fastest computers no matter how cleverly you code. The boundary between these two worlds is studied formally in **complexity theory**, and the rough map of that boundary is given by **complexity classes**: `P`, `NP`, `NP-Complete`, and `NP-Hard`. This lesson introduces those classes conceptually. You will see how `P` collects problems solvable in polynomial time, how `NP` collects problems whose solutions can be *verified* in polynomial time (even if finding them might be slow), and how `NP-Complete` and `NP-Hard` capture the hardest problems in `NP` and beyond. You will meet famous examples (Traveling Salesman, SAT, the knapsack problem), get a light introduction to **polynomial-time reductions** as the tool used to prove a new problem is `NP-Complete`, and confront the legendary `P vs NP` question along with why it matters for cryptography and the entire structure of computer science. This lesson assumes you are fluent with all the basic asymptotic machinery from **Asymptotic Analysis Fundamentals**, **Big-O Notation (Upper Bound)**, **Time Complexity Analysis Techniques**, **Space Complexity Fundamentals**, and **Little-o and Little-omega Notations**. Complexity classes use those same growth-rate ideas to draw lines between "polynomial" and "exponential" rather than between specific functions like `n^2` and `n log n`. From here you will move into **Amortized Analysis**, shifting from broad problem classification back to the fine-grained per-operation analysis that complex data structures demand.
Not Started
0%
Little-o and Little-omega Notations
When a paper claims an algorithm runs in `O(n^2)`, that statement leaves a question wide open: does the algorithm *actually* take quadratic time, or could the bound be loose? **Little-o** and **little-omega** are the notations that close that gap. `f(n) = o(g(n))` says `f` grows *strictly* slower than `g`, never matching its rate, and `f(n) = omega(g(n))` says `f` grows strictly faster. They are the precision tools of theoretical CS. This lesson defines both notations using the formal limit-based criterion: `f(n) = o(g(n))` iff `lim f(n)/g(n) = 0`, and `f(n) = omega(g(n))` iff `lim f(n)/g(n) = infinity`. You will prove and disprove `o` and `omega` claims for common function pairs (`n` vs `n^2`, `log n` vs `n`, `n` vs `n log n`, `2^n` vs `n^k`), use these notations to rank growth rates strictly, and see how the full five-notation system fits together: `O` and `Omega` allow equality, `Theta` requires it, while `o` and `omega` forbid it. This lesson builds on three earlier asymptotic foundations. From **Big-O Notation (Upper Bound)** you have non-strict ceilings; from **Big-Omega Notation (Lower Bound)** you have non-strict floors; and from **Big-Theta Notation (Tight Bound)** you have the exact-rate case. Little-o and little-omega simply require the inequality to be strict, ruling out the matching case that Big-O and Big-Omega permit. With all five notations under your belt, you will be ready for **Complexity Classes (Conceptual Overview)**, where these comparisons get used to separate classes like `P` and `NP`.
Not Started
0%
Modular Arithmetic
Open any production hash table, any block cipher, any RSA implementation, or any competitive programming problem that ends in "output the answer modulo `10^9 + 7`", and you will find the same machinery underneath: **modular arithmetic**, the math of working with remainders rather than full integers. It is the bridge between number theory and a huge swath of real algorithms. This lesson develops that machinery from first principles. You will revisit the `mod` operation precisely (including its relationship to division and remainders), then prove and use the addition, subtraction, and multiplication rules that let you take `mod` at every step of a long calculation without changing the answer. From there you will implement **fast modular exponentiation** in `O(log n)` time using binary exponentiation, compute **modular inverses** with **Fermat's Little Theorem** when the modulus is prime, and see exactly why hash tables, RSA, and contest problems rely on these tricks to avoid overflow and to invert multiplications. This lesson builds on **Number Theory Fundamentals**, where you learned about primes, divisibility, `gcd`, and the Euclidean algorithm. Modular arithmetic uses all of those: primality lets you apply Fermat, `gcd` decides when an inverse exists, and divisibility underlies every congruence. From here the only foundations topic remaining is **Basic Proof Techniques**, where you will learn the proof tools (induction, contradiction, contraposition) that make the kinds of arguments you have just been waving at fully rigorous.
Not Started
0%
Recurrence Relations
When you stare at merge sort or binary search, the running time is not naturally a simple sum like `n^2/2 + n/2`. It is something more interesting: the cost of a problem of size `n` is built out of the cost of smaller problems plus a little glue. That self-referential structure is captured by a **recurrence relation**, an equation of the form `T(n) = ...` written in terms of `T` on smaller inputs. This lesson teaches you to spot, write, and classify recurrences directly from recursive code. You will identify the two ingredients every recurrence needs (the recursive case and the base case), then translate familiar algorithms into their `T(n)` equations: factorial gives `T(n) = T(n-1) + 1`, binary search gives `T(n) = T(n/2) + 1`, merge sort gives `T(n) = 2 T(n/2) + n`, and naive Fibonacci gives `T(n) = T(n-1) + T(n-2) + 1`. You will also group recurrences into three families (linear, divide-and-conquer, and multi-branch) and recognize the Big-O class each typically produces. This lesson builds on **Big-O Notation (Upper Bound)**, which gave you the language for expressing complexity, and on **Mathematical Sequences**, which gave you experience with arithmetic, geometric, and Fibonacci-style sequences, exactly the patterns you will see when a recurrence is expanded. Writing a recurrence is half the battle; the other half is converting it into a closed-form Big-O. That is the subject of the very next lesson, **Solving Recurrence Relations**.
Not Started
0%
Solving Recurrence Relations
Writing the recurrence `T(n) = 2 T(n/2) + n` for merge sort is the easy part. Turning it into the closed-form `O(n log n)` is where the real algorithm analysis happens, and it is exactly what this lesson is for. **Solving Recurrence Relations** gives you a small toolkit that, used well, can analyze nearly every recursive algorithm you will meet in interviews, papers, or production. This lesson walks through five methods. The **Substitution Method** has you guess the solution and prove it by induction, useful when you already suspect the bound. The **Recursion Tree Method** visualizes work level by level and sums it; this is how you see why merge sort spends `n` work per level over `log_2(n)` levels. The **Master Theorem** mechanically solves the divide-and-conquer form `T(n) = a T(n/b) + f(n)` via three cases, and you will memorize when each case fires. The **Extended Master Theorem** patches the gap when `f(n)` includes logarithmic factors. The **Akra-Bazzi Method** generalizes to unequal subproblem sizes that the basic theorem cannot handle. You will practice picking the right tool for each recurrence rather than blindly reaching for the same one every time. This lesson directly continues **Recurrence Relations**, where you learned to write `T(n)` from recursive code, and reuses ideas from **Big-O Notation (Upper Bound)** and **Mathematical Sequences** for the underlying summation arguments. With the analysis sub-track complete, you will pivot back to advanced math in **Modular Arithmetic**, where number-theoretic tools meet algorithm design.
Not Started
0%
Data Structures
B-Trees and B+ Trees
A modern hard drive reads about 100 MB per second sequentially, but a single random seek still costs around 10 milliseconds; that gap is roughly seven orders of magnitude. A binary tree of a billion keys has 30 levels, which means 30 random seeks per lookup. **B-Trees and B+ Trees** keep each node fat enough to fill a disk page, branch into hundreds of children, and answer the same lookup in three or four seeks. That is why every relational database you have used relies on this family for its indexes. This lesson covers the B-Tree minimum-degree parameter `t` and the resulting key-and-child counts at every node, the proactive split during insert that keeps the height bounded by `O(log_t n)`, the merge-or-redistribute logic for delete, and the B+ Tree refinement that pushes all data to the leaf level and links those leaves together so range queries become a sequential scan after a single descent. In **Binary Search Tree (BST)**, every node held a single key and at most two children; that geometry is fine for memory but disastrous for disk because each comparison forces a separate I/O. B-Trees flip the design: keep every node wide so a single I/O resolves many comparisons at once. Next, **Splay Tree** explores a third self-balancing strategy in which the tree reshapes itself around access patterns rather than maintaining strict structural invariants.
Not Started
0%
Balanced BST (AVL / Red-Black)
Insert the keys 1, 2, 3, 4, 5 into a plain BST in that order and you do not get a tree at all; you get a right-leaning chain with `O(n)` search. The fix is to detect imbalance after every insert or delete and rotate the offending subtree back into shape, which is exactly what a **Balanced BST** does. AVL and Red-Black trees are the two most influential designs in this family. This lesson covers the balance factor (height of left subtree minus height of right subtree), AVL's strict `|bf| <= 1` invariant enforced by the four rotation cases (LL, RR, LR, RL), and Red-Black trees' five color and structural invariants enforced by recoloring plus rotations. You will trace insertions through both schemes, see why Red-Black trees do fewer rotations on average and so are preferred by C++ `std::map` and Java `TreeMap`, and analyze the height bound (`<= 2 log n`) that gives both their worst-case `O(log n)` guarantee. In **Binary Search Tree (BST)**, you implemented search, insert, and delete that respected the ordering invariant but said nothing about shape; the resulting `O(n)` worst case is precisely what self-balancing solves by maintaining a height invariant in addition to the ordering invariant. Next, **B-Trees and B+ Trees** generalize the same balanced-tree idea to nodes that hold many keys at once, an essential design choice for disk-resident data.
Not Started
0%
Fenwick Tree (BIT)
A complete Fenwick Tree implementation fits in fifteen lines of code, half the memory of a segment tree, and a smaller constant factor on every operation. The price of admission is that you only get prefix-style aggregates, but for the enormous class of problems that need exactly that, a **Fenwick Tree** (also called a Binary Indexed Tree, or BIT) is the right answer. This lesson covers the dynamic prefix-sum problem (static prefix sums are `O(1)` query and `O(n)` update; you want both in `O(log n)`), the `i & -i` lowbit trick that isolates the lowest set bit and implicitly defines which range each index covers, point update and prefix query in `O(log n)`, and the `prefix(R) - prefix(L-1)` identity that turns those into general range queries. You will also meet the difference-array technique that swaps the roles, supporting `O(log n)` range updates with `O(log n)` point queries. In **Arrays & Strings**, you saw how a flat array can encode rich structure when the indexing scheme is clever; the Fenwick tree pushes that idea further by letting binary representation itself carry the partition information. **Segment Tree** solved a more general version of this problem with explicit nodes; the BIT trades flexibility for simplicity and memory and wins on both metrics whenever prefix queries suffice. Next, **Sparse Table** addresses a different point in the trade space: arbitrary range minimum (and similar idempotent) queries, with `O(1)` queries when no updates are involved.
Not Started
0%
Persistent Data Structures
Cloning a 100k-element segment tree before every update so the previous version stays queryable costs `O(n)` time and space per update, which is unworkable. **Persistent Data Structures** achieve the same 'every past version is still queryable' guarantee in `O(log n)` extra time and space per update by sharing the unchanged subtrees between versions and only allocating new nodes along the path that actually changed. This lesson covers the path-copying technique on a persistent segment tree (each update returns a brand-new root that shares everything except a thin spine of new nodes with the previous version), the `O(log n)` point update and range query on any historical version, persistent arrays built on top of persistent segment trees, and persistent stacks and queues using the cons-list approach from functional programming. You will analyze the total space (`O(n + q log n)` for `q` updates) and apply the structure to k-th smallest in subarrays, time-travel queries, and offline-query reductions. In **Trees: Binary Tree Fundamentals**, a recursive subtree was a self-contained piece of data; structural sharing exploits exactly that property to reuse old subtrees in new versions. **Segment Tree** built the recursive aggregate-over-intervals shape that the persistent variant adapts directly, swapping in-place updates for path copying. Next, **Treap (Randomized BST)** returns to the BST family with a different twist: random priorities for expected balance and `O(log n)` split and merge primitives.
Not Started
0%
Segment Tree
Given an array and a stream of mixed queries (`sum(L, R)`, `min(L, R)`, plus single-index updates), prefix sums answer the queries in `O(1)` but pay `O(n)` for every update, while a raw array does the opposite. Neither extreme is acceptable when both updates and queries are frequent. A **Segment Tree** balances the two: every operation runs in `O(log n)` after an `O(n)` build. This lesson covers the recursive segment-tree shape (a binary tree where each node stores the aggregate over an array interval, and children split the parent's interval in half), the `4n` flat-array layout that maps perfectly onto an iterative or recursive implementation, point update and range query in `O(log n)`, and lazy propagation, where range updates deposit a tag at the highest covering node and push it down only when a later query forces it. You will apply the structure to range sum, range minimum, and range maximum queries, and see why the same template extends to any associative aggregate. In **Arrays & Strings**, a flat array gave you `O(1)` indexed access but no aggregate support; the segment tree layers a hierarchy of precomputed aggregates on top of that array. **Trees: Binary Tree Fundamentals** is where the recursive shape and the `O(h)`-stack traversal pattern came from, and you reuse both directly here. Next, **Fenwick Tree (BIT)** solves a narrower version of the same problem (prefix-only aggregates) with simpler code and half the memory.
Not Started
0%
Sparse Table
Range minimum queries on a fixed array do not need updates, so the segment tree's `O(log n)` query is leaving performance on the table. A **Sparse Table** flattens the query down to genuine `O(1)`: precompute the minimum of every power-of-2 length window, and any range `[L, R]` can be answered by combining two such windows that together cover it, exploiting the fact that `min(min(A), min(B)) = min(A union B)` when the windows overlap. This lesson covers the `O(n log n)` preprocessing that fills a 2D table indexed by `(start, log2_length)`, the `O(1)` query trick for idempotent operations such as min, max, GCD, and bitwise OR, the `log2_floor` precomputation that makes every query branch-free, and the slower `O(log n)` query needed when the operation is not idempotent (like sum). You will see why this structure is the right tool for the Range Minimum Query (RMQ) problem and an essential building block in algorithms like Lowest Common Ancestor in `O(1)` per query. In **Arrays & Strings**, a flat array stored values; here the same shape stores precomputed answers indexed by a length exponent. **Logarithms & Exponentiation** is what makes the geometry work: power-of-two windows tile the index space the way binary representations tile integers, and the `O(1)` query depends on `floor(log2(length))`. With Sparse Tables in your toolkit, the curriculum next pivots to specialized structures for strings, immutability, and bounded integer universes.
Not Started
0%
Splay Tree
Real workloads are rarely uniform. Web caches, compiler symbol tables, and network routers all access the same handful of items thousands of times in a row before moving on. A **Splay Tree** turns that observation into a balancing strategy: every access (search, insert, or delete) drags the touched node to the root through a sequence of rotations, so frequently used keys stay shallow and effectively pay `O(1)` after the first hit. This lesson covers the three splay rotation cases (zig, zig-zig, and zig-zag) that move a target node toward the root in pairs of levels, the modified search, insert, and delete operations that always end with a splay, and the amortized analysis that yields `O(log n)` per operation across any sequence of `m` operations even though individual operations can be `O(n)` in the worst case. You will also meet the working set theorem, which is the formal version of the temporal-locality intuition. In **Binary Search Tree (BST)**, accesses left the tree shape unchanged; balanced variants enforced strict structural invariants. The splay tree refuses both options and instead lets the access pattern itself reshape the tree, with no balance factor or color bit stored anywhere. Next, **Treap (Randomized BST)** keeps the same single-bit-of-extra-state simplicity but uses random priorities (rather than recent access) to control balance.
Not Started
0%
Suffix Array / Suffix Tree
Genome alignment tools like BWA and Bowtie find a 100-character read inside a 3-billion-base human reference in milliseconds, not by scanning the genome but by querying an index built once over all of its suffixes. **Suffix Array / Suffix Tree** is the family of data structures behind that workflow, and the same machinery powers full-text search, plagiarism detection, and the BWT-based compression in bzip2. This lesson covers the suffix array (a sorted array of starting positions of every suffix), the binary-search pattern match in `O(m log n)` for a pattern of length `m`, the LCP (Longest Common Prefix) array that captures shared prefixes between adjacent sorted suffixes, and the suite of substring problems the pair solves: longest repeated substring, number of distinct substrings, and longest common substring. You will also meet the suffix tree, a compressed trie of all suffixes that pushes pattern matching down to `O(m)` independent of text length, and weigh the suffix array's smaller memory footprint against the suffix tree's faster query. In **Arrays & Strings**, sorting and binary search worked over numbers; here the same primitives extend to strings, with a comparator that compares characters position by position. **Trie (Prefix Tree)** introduced the prefix-matching tree shape, and a suffix tree is a compressed trie built from every suffix of the input. Next, the curriculum explores data structures organized around a different axis entirely: preserving every historical version of themselves through time.
Not Started
0%
Treap (Randomized BST)
Implementing a Red-Black tree from memory under interview pressure is a known-hard task; the rotation cases alone are several hundred lines of careful pointer work. A **Treap** reaches the same expected `O(log n)` height in maybe sixty lines, with no color bits and no balance factor, by giving each node a random priority and asking the tree to satisfy two simple invariants at once. This lesson covers the dual structure (BST order on keys, heap order on randomly assigned priorities), the proof sketch that random priorities yield expected `O(log n)` height because the tree is shaped like a uniform random BST, and the two operations that make treaps unusually flexible: `split(key)` cuts the treap into 'less than' and 'greater or equal' pieces, and `merge` glues two treaps together when one contains only smaller keys. From those two primitives, insert, delete, k-th element, and even range reversal fall out naturally. You will also meet the implicit treap, where positions replace keys and the result behaves like a balanced array supporting `O(log n)` insert-at-index and slicing. In **Binary Search Tree (BST)**, you saw that an unlucky insertion order produced a chain; randomized priorities solve that by making any input look balanced in expectation, the same way randomized quicksort tames adversarial pivots. With treaps in hand, the curriculum next explores structures that exploit very different properties (such as bounded integer universes) to push performance beyond what comparison-based trees can offer.
Not Started
0%
Van Emde Boas Tree
For a set of 32-bit integers, balanced BSTs answer successor and predecessor queries in `log_2(2^32) = 32` comparisons, and hash tables cannot answer those queries at all. A **Van Emde Boas (vEB) tree** answers them in `log_2(log_2(2^32)) = 5`, by recursively halving the bit-length of the universe at each level rather than halving the number of elements. That doubly-logarithmic bound is one of the most striking results in data structure theory. This lesson covers the recursive vEB structure (an integer universe `[0, u-1]` is split into `sqrt(u)` clusters of size `sqrt(u)` plus a summary structure over which clusters are non-empty, applied recursively), the explicit `min` and `max` fields that short-circuit the recursion to a single level when possible, the `O(log log u)` analysis for insert, delete, member, successor, predecessor, min, and max, and the `O(u)` space cost that makes vEB trees practical only for moderate universes. In **Binary Search Tree (BST)**, the height (and thus the operation cost) was governed by the number of stored keys; the vEB tree is governed instead by the size of the integer universe, a fundamentally different parameter. **Heaps & Priority Queue** introduced fast min and max access through a structural invariant; vEB trees push that idea further by also providing fast `successor` and `predecessor` over the same set. With Van Emde Boas, the data structures track is complete; the algorithms track is where these structures come alive in real problem solving.
Not Started
0%
Algorithms
Advanced Bit Manipulation
Iterating over all subsets of every subset of an `n`-element set sounds like `4^n` work. The actual cost is `3^n`: each element is in three states (in the outer mask only, in both, or in neither), and the binomial theorem collapses the sum. Insights like that turn what looks like a complexity wall into a tight, elegant solution. **Advanced Bit Manipulation** collects those insights. You will generate Gray codes (adjacent values differ by one bit, used in error correction), enumerate all subsets of a bitmask via the `for (s = mask; s > 0; s = (s - 1) & mask)` template, and master bit tricks like isolating the lowest set bit with `x & -x`, turning it off with `x & (x - 1)`, counting trailing zeros, and swapping without a temp variable. The lesson also covers advanced XOR applications (range XOR, two missing numbers, XOR basis over GF(2)) and bitwise DP including profile DP for grid tiling. In **Bit Manipulation (Intro)**, you mastered the basic operators and the single-number XOR trick. This lesson treats bits as a full algorithmic medium. Next, **Complexity & Proof Intuition (Optional)** revisits the theoretical foundations behind everything built so far.
Not Started
0%
Advanced Search Algorithms
Plain BFS finds the shortest path through a 1000x1000 grid by exploring outward in concentric circles, examining about a million cells. A* with a Manhattan-distance heuristic walks almost straight to the target and examines a few thousand. Both algorithms use the same priority-queue framework; the only difference is that A* adds a heuristic estimate to the cost function and biases the search toward the goal. That single addition is what powers GPS, game-pathfinding, and motion planning in robotics. **Advanced Search Algorithms** covers the search refinements that go beyond plain BFS and DFS. You will implement A* with the `f(n) = g(n) + h(n)` cost function, derive what makes a heuristic admissible, and prove the optimality guarantee under admissibility. Bidirectional search runs BFS from both source and target until the frontiers meet, cutting `O(b^d)` to `O(b^(d/2))`. Iterative Deepening DFS combines BFS-style completeness with DFS-style `O(d)` memory, using repeated depth-limited DFS. The lesson finishes with two specialized array searches: Jump search at `O(sqrt(n))` for sorted arrays where binary search is awkward, and interpolation search at `O(log log n)` expected for uniformly distributed keys. In **BFS & DFS (Intro)**, you wrote the basic skeletons. **Graph Algorithms (Core)** introduced Dijkstra's priority-queue relaxation, which A* generalizes by adding the heuristic. Next, **Game Theory** turns to two-player adversarial search.
Not Started
0%
Advanced Tree Algorithms
Finding the lowest common ancestor of two nodes by walking up parent pointers is `O(n)` per query, fine if you ask once but ruinous if you ask a million times on a tree of a million nodes. Binary Lifting precomputes the `2^k`-th ancestor of every node in `O(n log n)` total, then answers LCA in `O(log n)` per query. The same compute-once-then-query-fast pattern unlocks an entire family of advanced tree algorithms. **Advanced Tree Algorithms** covers that family. You will implement LCA via Binary Lifting and via the Euler Tour plus Range Minimum Query approach, where flattening the tree turns subtree queries into array-range queries. Heavy-Light Decomposition splits the tree into chains so path queries become `O(log^2 n)` segment-tree operations. Centroid Decomposition splits a tree of `n` nodes into `O(log n)` layers and powers distance and path-counting queries. The lesson finishes with the rerooting technique for tree DP, which computes DP results for every choice of root in linear total time instead of the naive `O(n^2)`. In **Tree Algorithms**, you mastered recursion-based tree problems and BST operations. This lesson trades simple recursion for preprocessing-and-query structures on top of the tree. Next, **Advanced Search Algorithms** revisits BFS and DFS with heuristic refinements.
Not Started
0%
Approximation Algorithms
Vertex Cover is NP-hard: there is no known polynomial algorithm that finds a minimum cover. But a five-line greedy algorithm guarantees a cover whose size is at most twice the minimum, and the proof fits on a napkin. That guarantee, the approximation ratio, is the difference between a heuristic that might be terrible and an algorithm with a written contract about how far from optimal its answer can be. **Approximation Algorithms** introduces that contract-based view of NP-hard optimization. You will define approximation ratio formally and walk through the classic constant-factor algorithms: a 2-approximation for Vertex Cover via greedy maximal matching, an `O(log n)`-approximation for Set Cover via greedy element-counting, and a 2-approximation for Metric TSP that exploits the triangle inequality on top of an MST. The lesson then covers approximation schemes (PTAS, polynomial in `n` for any fixed `epsilon`; FPTAS, polynomial in both), with Knapsack FPTAS as the canonical example. Throughout, the lesson contrasts approximation algorithms with heuristics, where heuristics give no guarantee at all. In **Greedy (Intro)**, you saw simple greedy strategies and their correctness proofs. **Dynamic Programming (Advanced)** introduced 0/1 Knapsack as an NP-hard exact algorithm. This lesson asks the next question: when exact is too slow, how close to optimal can we provably get? Next, **Advanced Bit Manipulation** turns to bit-level tricks for `O(1)` and bitmask-DP solutions.
Not Started
0%
Branch and Bound
0/1 Knapsack is exponentially many subsets to consider, but commercial solvers like CPLEX and Gurobi answer instances with thousands of items in seconds. The trick is not better hardware but smarter exploration: at every node of the search tree, compute a cheap upper bound on what any completion of the partial solution could possibly achieve, and prune the entire subtree if that bound cannot beat the best solution found so far. That single discipline of provably-suboptimal pruning is what defines branch and bound. **Branch and Bound** introduces the framework as a refinement of backtracking. You will design bounding functions (typically a relaxation, like fractional knapsack as a bound for 0/1 knapsack), build state-space trees, and choose between three exploration strategies: FIFO (BFS-like), LIFO (DFS-like), and least-cost (priority queue). Classic applications include 0/1 Knapsack with the fractional-relaxation bound, the Traveling Salesman Problem, and the job-assignment problem. The lesson also draws the line between B&B and DP so you know when each is the right approach. In **Backtracking (Intro)**, you walked an implicit decision tree with choose, explore, unchoose. **Greedy (Intro)** taught you that locally optimal choices sometimes give global optima. Branch and bound borrows the search structure of one and the bounding intuition of the other. Next, **Divide and Conquer (Advanced)** turns to algebraic D&C tricks like Karatsuba and Strassen.
Not Started
0%
Complexity & Proof Intuition (Optional)
Comparison-based sorting cannot do better than `O(n log n)`. That is not a statement about merge sort or quick sort or any specific algorithm; it is a statement about every possible algorithm in this model, including ones nobody has invented yet. The proof is a counting argument over decision trees, and learning to read it changes how you reason about algorithmic limits forever. Lower bounds, NP-completeness, P versus NP, and loop invariants all live in the same theoretical neighborhood. **Complexity & Proof Intuition (Optional)** is an enrichment tour of that neighborhood. You will use loop invariants to prove iterative algorithms correct, revisit amortized analysis with the potential method, work through NP-completeness via polynomial-time reductions and the Cook-Levin theorem, examine the P vs. NP question and its implications, derive the `Omega(n log n)` comparison-sorting lower bound via decision trees, and meet the broader complexity zoo (co-NP, PSPACE, EXP). This lesson rests on three earlier ideas. **Asymptotic Analysis Fundamentals** gave you the language of growth rates that complexity classes refine. **Dynamic Programming (Intro)** and **Greedy (Intro)** showed you exact polynomial-time algorithms; this lesson asks which problems will never have one. This concludes the algorithms track. From here, the natural next step is sustained problem solving on hard interview problems and competitive programming contests that exercise the full toolkit you have built.
Not Started
0%
Computational Geometry
The sign of a single 2D cross product tells you whether three points turn left, turn right, or are collinear, and that one signed scalar is the workhorse behind almost every algorithm in the plane. Convex hulls, polygon area, segment intersection, and point-in-polygon tests all reduce to a sequence of cross-product evaluations with a careful eye on edge cases. Get the geometric primitive right and the rest of the field follows. **Computational Geometry** introduces those primitives and the algorithms built on them. You will start with cross products and the orientation test, then implement convex-hull algorithms three ways: Graham scan in `O(n log n)` (sort by polar angle, maintain a stack with the orientation invariant), Jarvis march in `O(nh)` for hulls with few vertices, and Andrew's monotone chain. The lesson then covers line-segment intersection, the sweep-line algorithm for many segments, the closest-pair-of-points algorithm in 2D, polygon computations using the Shoelace formula, and the ray-casting point-in-polygon test. In **Sorting (Elementary)**, you learned the comparison-based sorting that drives polar-angle preprocessing. **Divide and Conquer (Advanced)** taught you the closest-pair `O(n log n)` template via the strip combine step, which reappears here. Next, **Advanced Tree Algorithms** moves from planar geometry back to hierarchical structures with Binary Lifting and centroid decomposition.
Not Started
0%
Divide and Conquer (Advanced)
Multiplying two `n`-bit integers the way you learned in school takes `O(n^2)` digit operations. In 1960, Karatsuba showed that the same product can be computed with three recursive multiplications instead of four, dropping the cost to `O(n^1.585)`. A few years later Strassen pulled the same trick on matrix multiplication, replacing eight recursive multiplications with seven and breaking the `O(n^3)` barrier for the first time. Both algorithms are pure divide-and-conquer with cleverly engineered combine steps, and they remain the gateway to a deeper view of D&C as algebraic restructuring. **Divide and Conquer (Advanced)** walks through that view. You will derive Karatsuba multiplication and apply the Master Theorem to its `T(n) = 3T(n/2) + O(n)` recurrence. You will work through Strassen's seven-multiplication identity for `2 x 2` blocks and discuss when its higher constant factor pays off in practice. You will solve closest-pair-of-points in 2D in `O(n log n)` via the strip optimization in the combine step, and look at convex-hull computation through a divide-and-conquer lens. In **Divide and Conquer (Intro)**, you applied the Master Theorem to merge sort and quick sort. **Recursion Fundamentals** gave you the call-stack model these algorithms still inhabit. This lesson keeps the recurrence framework but engineers cleverer combine steps. Next, **Mathematical Algorithms** turns to number-theoretic computation.
Not Started
0%
Dynamic Programming (Advanced)
Edit distance, the minimum number of insertions, deletions, and substitutions to turn one string into another, is what every spell checker quietly computes when it suggests a correction. The DP table that solves it has `m * n` cells, each filled by looking at three neighbors. That single 2D recurrence is the gateway to a much larger family: longest common subsequence, knapsack, palindrome partitioning, regex matching, and many more. **Dynamic Programming (Advanced)** is where 1D DP graduates into the rest of the field. You will work through 2D grid and string DP (unique paths, edit distance, LCS, longest common substring), the knapsack family (0/1, unbounded, subset sum, coin change), sequence DP (LIS in `O(n^2)` and the patience-sorting `O(n log n)` variant, maximum product subarray, word break), string DP (palindromic subsequence and substring, regex and wildcard matching), DP on trees (diameter, max path sum, binary tree cameras), interval DP via matrix chain multiplication, and an introduction to bitmask DP for TSP and assignment problems. In **Dynamic Programming (Intro)**, you learned to define state, transition, and base cases on linear problems. This lesson layers a second dimension onto each. Next, **Advanced DP Techniques** introduces optimization tools that push DP beyond standard tabulation.
Not Started
0%
Advanced DP Techniques
Standard tabulation gets you `O(n^2)` DP. The Convex Hull Trick brings the same recurrence down to `O(n log n)` whenever the transition is a linear function of the previous state, and the speedup matters: contest problems with `n = 10^5` go from too-slow to fast enough on exactly that change. A whole sub-field of DP is dedicated to these recurrence-shaped optimizations, and this lesson is your entry into it. **Advanced DP Techniques** covers four directions of post-tabulation DP. Optimization methods include the Convex Hull Trick (offline sorted-slope and online Li Chao tree), Divide and Conquer DP for monotone-split problems, and Knuth's Optimization for optimal-BST-style recurrences. Digit DP teaches you how to count numbers with properties in a range `[L, R]` by carrying a tight-constraint flag through the recursion. Advanced bitmask DP solves TSP, Hamiltonian path, and grid-tiling profile DP. Probability DP turns recurrences over expected values into clean tables, and Kadane's algorithm generalizes to circular and 2D variants. In **Dynamic Programming (Advanced)**, you mastered multi-dimensional state and transitions. This lesson asks the next question: when the table is too big or the transition too slow, how do you optimize? Next, **Graph Algorithms (Advanced)** brings similar depth to graph theory.
Not Started
0%
Game Theory
Two players take turns removing stones from piles, the player who takes the last stone wins, and the entire winning strategy boils down to one calculation: XOR all pile sizes together, and you win if and only if the result is non-zero. That is Nim, and the surprise is not that it has a strategy but that the strategy is so compact. The Sprague-Grundy theorem extends the same idea to every impartial combinatorial game. **Game Theory** introduces the algorithmic side of two-player game analysis. You will work through Nim and its XOR strategy, then see how the Sprague-Grundy theorem assigns a Grundy number (nimber) to every position and how XOR-of-nimbers solves any sum of games. The lesson then moves to general game trees: minimax for optimal play, alpha-beta pruning for cutting branches that cannot affect the result, and move ordering for better pruning. You will analyze game states using DP, classifying positions as winning or losing by computing backward from terminal states, and meet retrograde analysis as a complete-game-state technique. In **Dynamic Programming (Intro)**, you learned to recurse on subproblems and cache results. **Recursion Fundamentals** gave you the call-stack model behind minimax and Grundy computation. Game theory recasts those tools as adversarial search. Next, **Randomized Algorithms** turns to a different way of taming worst-case inputs.
Not Started
0%
Graph Algorithms (Advanced)
Dijkstra's shortest-path algorithm silently assumes every edge weight is non-negative. Hand it a graph with one negative edge and it can produce a wrong answer with full confidence, because the greedy choice that drives the algorithm no longer reflects the true cost. Real graphs (financial arbitrage detection, currency exchange, time-aware routing) routinely contain negative edges, and that single gap motivates an entire second wave of graph algorithms. **Graph Algorithms (Advanced)** covers that wave. Minimum-spanning-tree algorithms include Kruskal's (sort edges and union components) and Prim's (grow a tree using a priority queue), along with the cut property that explains why both produce the same minimum weight. Shortest paths gain Bellman-Ford for negative edges and negative-cycle detection, plus Floyd-Warshall for all-pairs shortest paths in `O(V^3)`. Strongly connected components are tackled by Kosaraju's (two DFS passes) and Tarjan's (single DFS with low-link values). The lesson also covers articulation points, bridges, Euler paths and circuits via Hierholzer's algorithm, and a first conceptual look at NP-complete Hamiltonian paths. In **Graph Algorithms (Core)**, you implemented Dijkstra, topological sort, and cycle detection. **Union-Find (Disjoint Set Union)** gave you the near-constant-time merge-and-query primitive that makes Kruskal's MST run in `O(E log E)`. From here, **Advanced Graph Algorithms (Network Flow)** turns to capacity-constrained optimization on directed graphs.
Not Started
0%
Advanced Greedy & Data Structures
"For each element in the array, find the next greater element" is a brute-force `O(n^2)` problem until you notice that a stack maintained in decreasing order lets you answer every query as a side effect of a single left-to-right scan. The whole algorithm runs in `O(n)`, and the same monotonic-stack pattern solves trapping rain water, largest rectangle in a histogram, stock spans, and a long tail of related problems with the same template. **Advanced Greedy & Data Structures** is where greedy thinking meets specialized scaffolding. You will implement the monotonic stack pattern for next-greater and next-smaller variants, the monotonic deque for sliding-window maximum and minimum (also a key DP optimization), and sweep-line algorithms for interval and event problems (meeting rooms, interval merge, rectangle area union). The lesson closes with advanced greedy problems that need a heap or priority queue: full Huffman encoding, task scheduling with cooldown, the gas station problem, and activity selection with deadlines and profits. In **Greedy (Intro)**, you saw simple greedy strategies that needed only sorting. **Heaps & Priority Queue** taught you `O(log n)` access to the minimum or maximum, which is exactly what these advanced greedy patterns rely on for their efficiency. Next, **Branch and Bound** extends backtracking with the same kind of bounding-function pruning, applied to optimization search trees.
Not Started
0%
Mathematical Algorithms
Computing `a^b mod m` for `a = 7`, `b = 10^18`, and `m = 10^9 + 7` looks impossible: even iterating one multiplication per step would take longer than the age of the universe. Binary exponentiation does it in 60 multiplications, by squaring the base while halving the exponent. RSA encryption depends on exactly this trick, and so do most modular-arithmetic problems in competitive programming. **Mathematical Algorithms** assembles the standard toolkit. You will implement the Sieve of Eratosthenes for primes up to `N` in `O(N log log N)`, plus the segmented sieve for large ranges. Binary exponentiation handles `a^b mod m` in `O(log b)`, and the matrix-exponentiation generalization computes Fibonacci or any linear recurrence in `O(log n)`. You will derive the Extended Euclidean algorithm for `ax + by = gcd(a, b)` and use it for modular inverses, walk through the Chinese Remainder Theorem, compute Euler's totient, apply Fermat's Little Theorem to modular inversion, and run the Miller-Rabin probabilistic primality test. In **Number Theory Fundamentals**, you saw GCD, primes, and divisibility. **Modular Arithmetic** introduced congruences and modular inverses. This lesson turns those facts into algorithms that scale to numbers the problem statement actually asks about. Next, **Computational Geometry** turns to algorithmic problems on points, lines, and polygons.
Not Started
0%
Advanced Graph Algorithms (Network Flow)
Two seemingly different problems, the maximum amount of water you can push from a source to a sink through a network of capacitated pipes, and the minimum total capacity you must remove to disconnect the sink from the source, turn out to have the same answer for every graph. The max-flow min-cut theorem ties them together, and once you accept it a surprising number of optimization problems (image segmentation, project selection, bipartite matching) collapse into max-flow instances. **Advanced Graph Algorithms (Network Flow)** introduces the algorithms that compute that maximum flow. You will work through the Ford-Fulkerson method built on augmenting paths and the residual graph, the BFS-based Edmonds-Karp variant with its `O(V * E^2)` guarantee, and Dinic's algorithm which uses level graphs and blocking flows to reach `O(V^2 * E)`. The lesson then turns to maximum bipartite matching (Hungarian and Hopcroft-Karp), applications like airline scheduling and image segmentation, and a first look at minimum-cost flow. In **Graph Algorithms (Advanced)**, you handled MST, all-pairs shortest paths, and SCCs on edge-weighted graphs. Network flow keeps the weighted-edge model but flips the question from "shortest" to "highest throughput." Next, **String Algorithms** turns to pattern matching, the implicit automaton of a regular expression.
Not Started
0%
Pattern Matching Algorithms
Boyer-Moore is the algorithm `grep` actually uses, and it has a counterintuitive property: longer patterns make it _faster_, not slower, because the bad-character rule lets it skip whole chunks of the text without inspecting them. The best case is `O(n / m)`, sublinear in the text length. The same insight (start from the right, jump aggressively on mismatch) defines a different family of pattern-matching algorithms from the linear-scan family of KMP and Z. **Pattern Matching Algorithms** rounds out the string-search toolkit. You will implement Boyer-Moore with both the bad-character rule and the good-suffix rule, build a deterministic finite automaton (DFA) from a pattern and use the resulting state-transition table for `O(n)` matching after `O(m * |alphabet|)` preprocessing, and extend pattern search into two dimensions row by row. The lesson closes with a head-to-head comparison of every string-matching algorithm you have seen so far (KMP, Z, Rabin-Karp, Manacher, Aho-Corasick, Boyer-Moore, DFA), so you can pick the right tool for any matching task: long patterns, multi-pattern, streaming, or 2D. In **String Algorithms**, you mastered the failure-function family of linear-time matchers. This lesson adds the right-to-left family and the automaton-construction family. From here, **Advanced Greedy & Data Structures** turns to monotonic stacks.
Not Started
0%
Randomized Algorithms
Plain quick sort with a fixed pivot is `O(n log n)` on random input but `O(n^2)` on already-sorted input, the worst-case input an adversary can hand it. Pick the pivot uniformly at random instead, and the same algorithm becomes `O(n log n)` _expected_ on every input, because the adversary no longer knows where the algorithm will partition. Randomization is not a hack here; it is a principled way to break the dependency between input and runtime. **Randomized Algorithms** trains that style of thinking. You will distinguish Las Vegas algorithms (always correct, randomized running time) from Monte Carlo algorithms (bounded running time, possibly wrong) and reason about expected-value guarantees. You will analyze Randomized Quick Sort to see why expected `O(n log n)` is robust against adversarial input, implement Quick Select for `O(n)` expected-time kth-element selection plus the deterministic median-of-medians variant, and walk through Reservoir Sampling Algorithm R for uniformly sampling `k` elements from a stream of unknown length, including the proof of uniformity. The lesson also revisits skip lists and treaps from the data-structures track as randomized alternatives to balanced BSTs. In **Sorting (Elementary)**, you saw worst-case-sensitive sorting. **Recursion Fundamentals** gave you the call-stack model behind quick sort and quick select. This lesson injects controlled randomness into those frameworks. Next, **Approximation Algorithms** trades exactness for polynomial time on NP-hard inputs.
Not Started
0%
String Algorithms
Naive substring search compares the pattern against every position in the text, restarting from scratch on each mismatch, for `O(n * m)` worst-case time. KMP, by precomputing where to resume after a mismatch, never restarts. The text pointer moves forward strictly monotonically, the pattern pointer is corrected by a failure function, and the whole search runs in `O(n + m)`. That single insight defines a family of linear-time string algorithms that power editors, search engines, and bioinformatics pipelines. **String Algorithms** covers that family. KMP teaches you to build the failure function (prefix function) and use it to skip redundant comparisons. The Z algorithm offers an alternative `O(n)` framework based on the Z-array. Rabin-Karp introduces rolling hashes for multi-pattern search and is the backbone of plagiarism detection. Manacher's algorithm finds the longest palindromic substring in linear time using a clever transform with separators. Aho-Corasick generalizes KMP to multiple patterns simultaneously by adding failure links to a trie, producing a finite automaton that scans the text once. In **Arrays & Strings**, you treated strings as arrays of characters with `O(1)` indexed access. **Hash Map (Dictionary) Basics** gave you the `O(1)` lookup used by Rabin-Karp. This lesson layers algorithmic structure on top of those primitives. Next, **Pattern Matching Algorithms** extends the toolkit with Boyer-Moore, DFA-based matching, and 2D pattern search.
Not Started
0%
Practice Problems
Alien Dictionary
Given a sorted list of words in an alien language, determine the order of characters in the alien alphabet using topological sort.
Basic Calculator
Implement a basic calculator to evaluate a string expression containing '+', '-', parentheses, and non-negative integers.
Binary Tree Maximum Path Sum
Given the root of a binary tree, return the maximum path sum where a path is any sequence of connected nodes (not necessarily passing through the root).
Burst Balloons
Given n balloons with numbers on them, burst them wisely to maximize the total coins collected, where bursting balloon i earns nums[left] * nums[i] * nums[right].
Candy
Given an array of children's ratings, distribute the minimum number of candies such that each child gets at least one and children with higher ratings get more candies than their neighbors.
Distinct Subsequences
Given two strings s and t, return the number of distinct subsequences of s which equals t.
Find Median from Data Stream
Design a data structure that efficiently finds the median from a stream of integers using two heaps.
Largest Rectangle in Histogram
Given an array of bar heights representing a histogram, find the area of the largest rectangle that can be formed within the histogram.
Longest Increasing Path in a Matrix
Given an m x n integer matrix, find the length of the longest strictly increasing path where you can move in four directions.
Max Points on a Line
Given an array of points on a 2D plane, find the maximum number of points that lie on the same straight line.
Maximum Profit in Job Scheduling
Given jobs with start times, end times, and profits, find the maximum profit you can earn by scheduling non-overlapping jobs.
Maximal Rectangle
Given a 2D binary matrix filled with '0's and '1's, find the area of the largest rectangle containing only '1's.
Median of Two Sorted Arrays
Find the median of two sorted arrays in O(log(min(m, n))) time by binary searching for the correct partition.
Merge k Sorted Lists
Merge k sorted linked lists into one sorted linked list using a divide-and-conquer or min-heap approach.
Minimum Interval to Include Each Query
Given a list of intervals and a list of queries, for each query find the size of the smallest interval that contains it, or -1 if no interval contains it.
Minimum Window Substring
Find the smallest substring of s that contains all characters of t, including duplicates.
N-Queens II
Given an integer n, return the number of distinct solutions to the n-queens puzzle, where n queens are placed on an n x n chessboard so that no two queens attack each other.
N-Queens
Place n queens on an n x n chessboard so that no two queens attack each other. Return all distinct board configurations as lists of strings, where 'Q' represents a queen and '.' represents an empty space.
Reconstruct Itinerary
Given a list of airline tickets, reconstruct the itinerary in lexical order starting from 'JFK', using all tickets exactly once.
Regular Expression Matching
Implement regular expression matching with support for '.' (matches any single character) and '*' (matches zero or more of the preceding element).
Reverse Nodes in k-Group
Given the head of a linked list, reverse the nodes of the list k at a time, and return the modified list. Nodes left over at the end that are fewer than k should remain in their original order.
Serialize and Deserialize Binary Tree
Design an algorithm to serialize a binary tree to a string and deserialize the string back to the original tree.
Sliding Window Maximum
Find the maximum value in each sliding window of size k as it moves across the array.
Best Time to Buy and Sell Stock III
Find the maximum profit from at most two stock transactions, where you must sell before buying again.
Best Time to Buy and Sell Stock IV
Find the maximum profit from at most k stock transactions, generalizing the Stock III problem to arbitrary k.
Substring with Concatenation of All Words
Find all starting indices where a concatenation of all given words (each of equal length) forms a substring.
Swim in Rising Water
Given an n x n grid of elevations, find the minimum time t at which you can swim from the top-left to the bottom-right corner.
Text Justification
Given an array of words and a maximum width, format the text so that each line has exactly the specified number of characters, fully justified (left and right).
Trapping Rain Water
Given an elevation map, compute how much water it can trap after raining.
Word Ladder
Given a begin word, end word, and a dictionary, find the length of the shortest transformation sequence where each step changes exactly one letter.
Word Search II
Given a 2D board of characters and a list of words, find all words that can be formed by sequentially adjacent cells on the board, using each cell at most once per word.
System Design
Data Warehousing, Data Lakes & OLAP vs OLTP
OLTP databases are built for fast single-row reads and writes; analytical queries against them choke. This lesson covers why analytics needs its own storage stack: column-oriented warehouses, lake formats, and lakehouse engines that scan billions of rows in seconds. You'll learn the OLTP versus OLAP trade-off, dimensional modeling (star schema), ETL versus ELT, change data capture, and how a modern data platform separates compute from storage so you can query petabytes for the cost of a coffee.
Leader Election & Consensus (Raft, Paxos)
Leader election is how a distributed cluster picks one node to be in charge so the others can stop arguing. This lesson covers the consensus problem (FLP impossibility), Paxos in concept, Raft in detail (leader election + log replication + safety), the role of quorum, and the operational pitfalls of split brain and network partitions. We also tour the systems that ship Raft or Paxos in production: etcd, ZooKeeper, Consul, CockroachDB, MongoDB, Spanner. By the end you can explain why every modern distributed database has a consensus protocol at its core, and you can sketch Raft on a whiteboard.
Distributed Transactions (2PC, Saga Pattern)
When a single business operation spans multiple services or databases, you cannot rely on a single ACID transaction. This lesson covers the two dominant patterns for keeping consistency across services: Two-Phase Commit (2PC) for synchronous, atomic, blocking transactions, and the Saga pattern (orchestration vs choreography) for long-running asynchronous workflows with compensating actions. We also cover Three-Phase Commit, idempotency keys, the outbox pattern, and the trade-offs that explain why 2PC is rare in microservices and Sagas are everywhere. By the end you can pick the right pattern for an order checkout, a money transfer, or a multi-step booking flow.
Stream Processing (Kafka Streams, Flink)
Stream processing is the discipline of computing on continuous, unbounded data as it arrives, instead of in periodic batches. This lesson covers the core stream-processing primitives: stateful operators, event time vs processing time, watermarks, windowing (tumbling, sliding, session), exactly-once semantics, and stateful checkpointing. We compare the leading engines (Kafka Streams, Apache Flink, Spark Structured Streaming) and walk through real production patterns: real-time analytics, fraud detection, ML feature pipelines, and CDC-driven materialized views. By the end you can sketch a Flink pipeline on a whiteboard and defend the windowing and checkpointing choices.
Design TikTok (Short-Form Video)
Design TikTok with 1.5B monthly active users, 100M short videos uploaded daily, and the For You Page that decides which video plays next for every viewer in under 100 ms. Unlike Instagram and Twitter, TikTok has no follower-driven feed - the For You Page is pure ML recommendation from a global pool. The interview centerpiece is the recommendation system architecture: candidate retrieval, two-tower models, online ranking with engagement signals, and how to keep video pre-loaded so the next swipe is instant. We also cover content moderation at scale, edge caching for the long-form-of-short-form access pattern, and why TikTok's product choice eliminated the celebrity fan-out problem entirely.
Design Facebook News Feed
Design Facebook's News Feed for 2 billion daily active users where every feed open reads from a personalized, ML-ranked timeline assembled from thousands of candidate posts in real time. Unlike Instagram's chronological precomputed feed or TikTok's pure recommendation, Facebook blends a friend graph, group memberships, page follows, and ads into one ranked stream via the legendary EdgeRank-and-successor algorithms. The interview centerpiece is the aggregator pattern: parallel candidate retrieval from many sources, real-time feature lookup, ML scoring, and online filtering, all under a 200 ms p99 budget. We also cover real-time updates (push notifications when a friend posts), edge ranking signals, and how Meta keeps the feed fresh with no precomputed timeline.
Design Video Conferencing (Zoom)
Design a real-time video conferencing system like Zoom that supports 1-on-1 calls and meetings of up to 1000 participants with sub-200ms glass-to-glass latency, adapts to user bandwidth, and runs reliably across mobile networks. The interview centerpiece is the choice of media topology: peer-to-peer mesh (small calls), MCU mixing (centralized, expensive), or SFU forwarding (the modern standard). We cover the WebRTC stack (signaling vs media planes, ICE/STUN/TURN), simulcast and SVC for adaptive quality, recording pipelines, and how to keep latency low when participants span multiple continents.
Design Discord (Real-time Communities)
Design Discord, a real-time community platform with 200M monthly active users, organized into 'guilds' (servers) of up to 500K members each, with persistent text channels storing trillions of messages and live voice channels with sub-100ms latency. The interview centerpiece is the dual architecture: a sharded text-message store (Cassandra/ScyllaDB) with billions of messages per guild and per-channel ordering, plus a real-time voice infrastructure with regional voice servers and custom UDP transport. We cover guild sharding by Snowflake ID, the Elixir/Erlang gateway that holds millions of WebSocket connections, presence at the guild scale, and how Discord migrated from MongoDB to Cassandra to ScyllaDB as message volume crossed trillions.
Design a Search Engine
Design a web-scale search engine that indexes 50B documents and serves 100K queries per second with sub-200ms p99 latency, ranking results by relevance (BM25), authority (PageRank), and personalization. The interview centerpiece is the inverted index sharded across thousands of nodes with scatter-gather query execution, plus the multi-stage ranking pipeline (cheap candidate generation, expensive learned-to-rank rerank). We cover document parsing and tokenization, the offline indexing pipeline (Spark MapReduce), term-partitioned vs document-partitioned sharding, query understanding and expansion, snippet generation, and how to keep the index fresh as the web changes.
Design a Payment System (Stripe)
Design a Stripe-style payment platform that processes 100M payments per day across 50 currencies and dozens of payment methods, where the central requirement is financial correctness: never charge a customer twice, never lose a payment, always reconcile to the cent. The interview centerpiece is the trio of idempotency keys, the payment intent state machine, and the immutable double-entry ledger - together they make the system safe in the face of network failures, partial outages, and adversarial retries. We also cover webhook delivery with signing and exponential backoff, PCI scope minimization through tokenization, multi-region availability, and the reconciliation jobs that compare our ledger to the bank's settlement files every night.
Design Object Storage (S3)
Design an S3-style object storage service that stores trillions of immutable blobs ranging from 1 KB to 5 TB at eleven nines of durability and a fraction of the cost of triple replication. The interview centerpiece is the trio that makes this economical: erasure coding (typically 12 data shards plus 4 parity shards) instead of full replicas; a separate metadata service that maps object keys to chunk locations; and multi-part upload that lets a 5 TB object stream from many sources in parallel. We also cover the bucket/object namespace, lifecycle policies that move cold objects to colder tiers, immutability with versioning, pre-signed URLs for direct client transfer, and the move from eventual to strong read-after-write consistency that AWS shipped in 2020.
Design a Distributed File System (GFS/HDFS)
Design a Google-File-System or HDFS-style distributed file system that stores petabytes across commodity hardware, optimized for batch analytics workloads where files are large (gigabytes), reads are sequential, and writes are append-mostly. The interview centerpiece is the leader-based architecture: one strongly-consistent master node holds the entire file namespace and chunk locations in memory, while many chunkservers store the actual data in 64-128 MB chunks replicated three times across racks. We cover the lease-based primary-replica protocol that lets the master stay out of the data path, the heartbeat-and-chunk-report mechanism that keeps cluster state fresh, and the federation strategy for scaling beyond a single master's memory.
Design Google Maps
Design Google Maps: a global mapping service that renders the Earth from 256x256 tiles, computes the shortest driving route in under 200 ms, and folds live traffic into routing for 1B users issuing 5B route requests per day. The interview centerpiece is the routing engine: how Dijkstra is too slow on a continent-scale graph and how Contraction Hierarchies (CH) precompute shortcuts so the live query is logarithmic. We cover the tile pyramid (zoom 0-20, ~1 trillion possible tiles at zoom 20), how live traffic from 100M Android phones updates edge weights every minute, and how to keep navigation latency under 1 second when re-routing.
Design Google Docs (Collaborative Editing)
Design a real-time collaborative document editor like Google Docs where 1B+ users can co-edit the same document with sub-200 ms latency, never lose a keystroke, and converge to the same state across all clients regardless of network conditions. The interview centerpiece is concurrency control: how to merge two users' simultaneous edits without conflicts. We compare Operational Transformation (OT, used by Google Docs) and Conflict-free Replicated Data Types (CRDT, used by Figma, Notion, Linear), explain the convergence problem (TP1, TP2 properties), walk through cursor presence, and design the document storage as an append-only operation log compacted into snapshots.
Design a Stock Exchange
Design a stock exchange like NASDAQ that matches buy and sell orders for thousands of symbols at sub-100-microsecond latency, handles 200K orders per second per symbol at peak, and produces a deterministic, replayable trade history with regulatory audit guarantees. The interview centerpiece is the matching engine: a deliberately single-threaded, in-memory order book that processes orders sequentially in price-time priority. We design the order book data structures (price-indexed levels with FIFO queues), the gateway path (ultra-low-latency parsing and rate-limit), the event-sourced persistence (every order and trade as an append-only event), and how to scale by sharding per symbol.
Authentication & Authorization (OAuth2, JWT, RBAC)
Authentication answers 'who are you?'. Authorization answers 'what are you allowed to do?'. Most systems get both wrong in subtle ways: rolling their own crypto, treating JWTs as a session store, copying RBAC into every service, or never thinking about how to revoke a leaked credential. This lesson covers the standard building blocks: password storage with adaptive hashing, session vs token authentication, OAuth2 and OIDC flows, JWTs and their honest trade-offs, RBAC vs ABAC vs ReBAC, multi-tenant authorization at scale, machine-to-machine auth (API keys, mTLS, workload identity), and the operational concerns (key rotation, revocation, audit). The goal is to leave you able to design and defend the auth architecture for any system, from a single product to a federated multi-tenant platform.
Data Pipelines & ETL/ELT
Data pipelines move data from operational systems (your transactional databases, event logs, third-party APIs) into analytical systems (warehouses, lakes, search indexes, ML feature stores). The 'shape' of the pipeline (ETL vs ELT, batch vs incremental, push vs pull) determines latency, cost, and how painful schema changes will be. This lesson covers the architectural choices: ingestion patterns, transformation engines (dbt, Spark, Beam), orchestration (Airflow, Dagster, Prefect), data quality, lineage, and the standard production layout (raw / staging / mart). It also covers the failure modes you must design for: late-arriving data, idempotency, backfills, schema evolution, and the silent corruption that comes from not testing your pipelines.
Microservices vs Monolith: When to Choose What
Microservices are not a maturity badge. Monoliths are not a code smell. The honest interview answer is that architecture is a continuum (monolith, modular monolith, services, microservices) and the right point on it is set by team size, deployment frequency, and the cost of distribution, not by what the cool kids at Netflix did. This lesson walks through the trade-offs concretely: latency tax, operational overhead, organizational coupling (Conway's Law), data consistency, and the migration paths that work. By the end you can defend either choice for a given product without reaching for buzzwords.
The System Design Interview Framework (RESHADED)
A system design interview is 45-60 minutes to design something the interviewer has been thinking about for years. Without a framework you will spend the first 20 minutes flailing, the next 20 deep in one corner, and the last 20 watching the interviewer try to redirect you. The RESHADED framework (Requirements, Estimation, Schema / API, High-level design, Architecture deep dive, Edge cases, Done / wrap-up) gives you a defensible structure that maps to how senior engineers actually think. This lesson walks through every stage with concrete tactics: the questions to ask in Requirements, the back-of-envelope numbers to estimate, the layer to draw first in HLD, the components to deep-dive into, and how to read the interviewer's signals to know what they want next. By the end you can walk into any system design interview with a known opener and a sequence of moves that work for any prompt.
Batch vs Stream Processing (Lambda/Kappa)
Batch processing computes results over a finite, bounded dataset. Stream processing computes results continuously over an unbounded, ever-arriving dataset. The two paradigms have different latency, cost, correctness, and operational profiles, and choosing wrong is one of the most expensive architectural mistakes a senior engineer can make. This lesson covers the mental model (bounded vs unbounded data, event time vs processing time, watermarks, windows), the two classical reference architectures (Lambda and Kappa), the modern unified models (Beam, Flink), and the production realities of exactly-once semantics, late data, replays, and operational complexity. The goal is to leave you able to choose batch, streaming, or a hybrid for any system, and to defend the choice in an interview.
Encryption at Rest/Transit & Data Privacy (GDPR)
Encryption protects data from unauthorized access; privacy regulations (GDPR, CCPA, HIPAA, PCI-DSS) determine what data you may collect, how you must protect it, who can see it, and how you must respond to user requests. The two intersect: regulations mandate encryption in many cases, and encryption is the technical foundation for most privacy controls. This lesson covers the standard primitives (TLS 1.3 for transit, AES-GCM and envelope encryption for rest), key management (KMS, HSM, key rotation), application-level encryption (per-tenant keys, field-level encryption, deterministic encryption for searchability), the privacy-engineering layer (data classification, minimization, retention, right-to-be-forgotten), and the operational realities (key compromise, crypto-shredding, BYOK, audit logs). The goal is to leave you able to design a system that is encryption-correct, privacy-compliant, and operationally honest about its trade-offs.
Event Sourcing & CQRS
Event Sourcing stores every change to your application state as an immutable event, and the current state is what you get when you replay them. CQRS splits the read and write paths so each can be optimized independently. Together they unlock auditability, time travel, and read/write scaling that traditional CRUD cannot. They also introduce eventual consistency, schema evolution pain, and a steep operational learning curve. This lesson teaches the mechanics, the implementation patterns (event store, snapshots, projections, sagas), and the honest answer to when these patterns are worth the cost (financial ledgers, audit-heavy domains, complex business workflows) and when they are over-engineering (a typical SaaS CRUD app).
Back-of-the-Envelope Estimation & Capacity Planning
Back-of-the-envelope estimation is the math you do in three minutes to ground a system design in numbers. It is what tells you whether your single Postgres instance can handle the load (no), how much storage you need over five years (probably more than you think), and how much CDN bandwidth you are about to commit to (probably more than that). This lesson covers the standard latency / throughput / size / bandwidth numbers every engineer should have memorized, the unit conversions and order-of-magnitude reasoning that keep you fast, the templates for QPS, storage, and bandwidth estimation, capacity planning beyond steady state (peak vs average, headroom, growth, regional, seasonal), and the cost rough-arithmetic that turns 'we need more servers' into a defensible business case. The goal is to leave you able to walk into any interview or design review and produce useful numbers in three minutes flat.
DDoS Protection, WAF & Security Best Practices
DDoS attacks try to exhaust your bandwidth, your TCP stack, your application capacity, or your downstream dependencies. A WAF (web application firewall) tries to block exploit traffic before it reaches your code. Together with rate limiting, bot management, anti-abuse tooling, and a hardened application layer, they form the defensive perimeter that real production systems live behind. This lesson covers the layered defense: edge / CDN scrubbing for L3/L4 floods, rate limiting and bot detection for L7 abuse, WAF rules for OWASP-class exploits, the OWASP Top 10 with concrete mitigations, secure development practices (input validation, output encoding, secrets management, dependency hygiene), incident response, and the operational realities of running this stack (false positives, vendor selection, escalation, post-mortems). The goal is to leave you able to design and defend the security perimeter for any user-facing system.
ML System Design (Feature Store, Model Serving)
An ML system in production is mostly a data system with a model in the middle. The model is the smallest, most-discussed, and least-troublesome part. The hard parts are training data pipelines, feature freshness and parity between training and serving, the feature store that enforces that parity, model deployment and rollback, online and offline evaluation, and the operational concern that the model silently degrades as the world drifts. This lesson covers the canonical reference architecture: training pipeline, feature store with online and offline halves, model registry, serving infrastructure, monitoring, and the feedback loop. It is the senior-level mental model for designing 'add ML to product X' without falling into the standard traps.
Service Mesh, Sidecar & Service Discovery
Once you have more than a handful of services, the cross-cutting concerns (mTLS, retries, circuit breaking, load balancing, traffic shifting, observability) start to dominate. Doing them in every service in every language is a maintenance nightmare. The sidecar pattern moves these concerns into a co-located proxy that runs next to your service, and a service mesh is the control plane that programs every sidecar in your fleet from one place. This lesson covers how a mesh actually works (data plane vs control plane, Envoy as the de-facto data plane, Istio and Linkerd as control planes), how service discovery underpins it, and the very real cost (latency tax, complexity, on-call burden) so you know when a mesh helps and when it is over-engineering.
Recommendation Systems Architecture
A recommendation system at scale is a multi-stage funnel: candidate generation narrows millions of items to a few thousand, light ranking trims to a few hundred, heavy ranking scores those, and a re-ranking stage applies business and policy constraints. Each stage has a different latency budget, a different model, and a different operational profile. This lesson covers the canonical architecture (retrieval + ranking + re-ranking), the core algorithmic families (collaborative filtering, content-based, two-tower neural retrieval, sequential models), the embedding store and vector ANN serving stack, the cold-start problem, ranking objectives and the metrics that measure them, and the rollout / monitoring discipline that keeps the system honest. The goal is to leave you able to design the recommendation system for any consumer product and defend every layer's choices.
Serverless Architecture & FaaS
Serverless does not mean 'no servers'. It means the cloud provider runs the servers, scales them to zero when idle, and bills you per request rather than per running hour. Functions-as-a-Service (Lambda, Cloud Functions, Cloud Run, Azure Functions) is the most visible flavor. The pattern is genuinely powerful for spiky workloads, glue code, and small teams who want to skip the infrastructure tax. It is genuinely a bad fit for steady high-throughput services, latency-critical paths, and stateful systems. This lesson covers how serverless actually executes (cold starts, warm pools, concurrency limits), the architectural patterns it enables, the patterns it breaks, and the honest cost model.
Multi-Region, Multi-Tenant Architecture
Going from one region to many is one of the largest architectural commitments a company can make. The motivations are real (latency for global users, regulatory data residency, disaster recovery, regional uptime SLOs) and so are the costs (cross-region replication latency, conflict resolution, deployment complexity, blast-radius management, double or triple infrastructure spend). Multi-tenancy adds another orthogonal axis: how do you share the same infrastructure safely across hundreds or thousands of customers without one of them noisy-neighboring everyone else? This lesson covers active-active vs active-passive deployments, the data layer (replication, conflict handling, GDPR-style data residency), DNS and traffic routing, deployment topology, and the tenancy patterns (silo, pool, bridge) along with when each is the right answer.
Search Indexing at Scale (Elasticsearch)
Search at scale is two systems in one: an indexing pipeline that ingests, transforms, and stores documents into an inverted index (and increasingly a vector index), and a query path that distributes searches across shards, scores results, and merges them under tight latency budgets. Elasticsearch and OpenSearch are the dominant production engines, and almost every large product runs one. This lesson covers the architecture: how Lucene segments and inverted indexes work, how Elasticsearch shards and replicates them, the tokenization and analyzer pipeline that determines what 'matches' mean, the query coordinator -> shard fan-out -> merge flow, hybrid search (lexical + vector), reindexing strategies, and the operational realities (hot shards, mapping explosions, garbage collection pauses, write amplification). The goal is to leave you able to design and operate search for any catalog from a million to billions of documents.
