Learn DSA
A structured path through data structures and algorithms. The articles build on each other, so follow the order if you're starting fresh — or jump to whatever you want to brush up on. Most posts include interactive visualizations you can step through.
Practice: pattern-wise questions
Curated LeetCode and GFG questions grouped by pattern — each one explained with examples, multiple approaches, and a dry run.
0 of 39 articles read
Progress is saved in your browser.
Foundations
How to reason about running time, recursion, and the two search/sort ideas everything else builds on.
Start here — the call stack model explains how every recursive algorithm in later phases actually runs.
Bubble, insertion, and merge sort as a first tour of comparing algorithms by their complexity.
The halve-the-problem idea, first over arrays and then as a tree structure.
AND, OR, XOR, and shifts — a small toolbox that keeps reappearing in hashing and optimization tricks.
Core data structures
The structures behind almost every practical program — and most interview questions.
How a sequence sits in memory — the trade-off between instant access and cheap inserts that every later structure inherits.
Pointer manipulation basics plus the classic fast/slow-pointer cycle trick.
Turning any key into a number — the idea a hash map is built on, and why collisions can never be fully avoided.
What actually makes lookups O(1): hashing, buckets, collisions, and resizing.
The array-backed tree that always knows its minimum — the engine behind schedulers and top-K problems.
A heap-driven greedy algorithm with a proof: merge the two rarest symbols, and get the optimal prefix code behind gzip and PNG.
A tree keyed by characters instead of comparisons; the structure behind autocomplete.
Algorithmic patterns
Reusable solution shapes — recognizing the pattern is most of the work in solving a new problem.
The pattern that turns a whole family of O(n²) array and string problems into O(n).
Expand around each of the 2n − 1 centres: a simple O(n²) answer with O(1) memory, and when DP or Manacher fits better.
Precompute once, answer range queries with a subtraction — the cheapest big win in array problems.
Binary search without a sorted array: search the range of possible answers, using a yes/no check that flips exactly once.
A stack that stays ordered, and the four "nearest greater/smaller element" questions it answers in O(n).
The monotonic stack with a moving left edge: a deque that gives every window's maximum in O(n).
Divide-and-conquer and heap ideas applied back to sorting — partitioning shows up far beyond sort itself.
Partition once, keep only the side with the answer — the kth smallest element in expected O(n).
A heap holding one candidate per sorted list — the pattern behind external sorting and merging k lists in O(N log k).
BFS and DFS are the entry point to every graph problem: reachability, shortest paths, cycles.
Grids are graphs in disguise: BFS from every unvisited land cell counts islands — and solves a whole family of grid problems.
BFS with two alternating colours: split a graph into two sides, or find the odd cycle that makes it impossible.
The same problem solved twice — an O(n²) dynamic program, then the O(n log n) version built on a binary search.
Overlapping subproblems, memoization, and tabulation — the pattern people find hardest, made mechanical.
The classic "choose a subset under a budget" DP — a two-dimensional table, then the one-array version that iterates backwards.
A two-string DP table, the walk back that recovers the answer, and how the same idea produces the diffs in code review.
When the state must remember a set: encode it as bits, and n ≤ 20 problems become 2ⁿ·n states instead of n! orders.
Putting it together
Problems that combine several structures at once — the shape real systems (and hard interviews) take.
A hash map and a doubly linked list working together for O(1) everything — a capstone for phases 1–3.
Systematic search over choice trees: permutations, subsets, and constraint problems.
Near-constant-time connectivity queries, and the trick behind Kruskal’s algorithm.
Prefix sums that survive updates — the same range queries in O(log n), built out of one bit trick.
Kruskal and Prim: union-find and priority queues applied to the cheapest way to connect everything.
Weighted graphs — where BFS stops working and priority queues take over.
Where Dijkstra’s greedy step breaks: negative edge weights, and detecting negative cycles.
Dijkstra plus a heuristic: the same loop, guided toward the goal, and the conditions that keep it optimal.
Two depth-first passes find every group of nodes that can all reach each other — and turn any directed graph into a DAG.
Precompute ancestors at powers of two, and any tree query — LCA, k-th ancestor, distance — takes O(log n) jumps.
Augmenting paths by BFS, residual edges that undo earlier choices, and the min cut that falls out — plus matching problems that reduce to it.