SeriesProgramming
DSA & Algorithms in Python
A 52-part course through data structures and algorithms, every one implemented and explained in Python.
51 parts17h totalMar 20, 2026 — Aug 9, 2026
- What Is DSA? Data Structures and Algorithms Explained for Complete BeginnersWhat data structures and algorithms actually are, why the wrong structure costs a factor of a million, an intuitive first look at Big O, and which language to learn it all in.18 min
- Python From Zero: The Complete Beginner's Guide to the LanguagePython from zero: where it came from, how to install it, and every part of the core language, plus what the language is really used for and which editor to learn in.46 min
- Big O Notation: How to Measure an Algorithm Without Running ItBig O from the counting argument up: what the formal definition promises, why constants vanish, how to read a bound off code, and the Master Theorem worked through.25 min
- Bubble Sort in Python: The Algorithm Everyone Learns FirstBubble sort explained by counting its comparisons: how the passes work, where the n squared comes from, the one boolean that makes its best case linear, and what to use instead.13 min
- Selection Sort in Python: The Fewest Swaps of Any Simple SortSelection sort makes exactly n-1 swaps on any input, the lowest worst case of any simple sort. Why that matters, why it is neither stable nor adaptive, and how heap sort fixes it.17 min
- Insertion Sort in Python: The Fast One Nobody ExpectsInsertion sort by the numbers: shifts equal inversions, which is why sorted input costs one linear pass, nearly-sorted input costs O(n times k), and Timsort still uses it.16 min
- Merge Sort in Python: Guaranteed O(n log n), Every Single TimeMerge sort explained by counting its work: the split, the merge that does all the real sorting, why every input costs n log n, and how it sorts files larger than memory.16 min
- Quick Sort in Python: The Fastest Sort in Practice, and Its One WeaknessHow partitioning works, why Lomuto and Hoare differ, and why the pivot rule decides everything: 2,698 comparisons or 79,800 on the same 400 items.14 min
- Heap Sort in Python: O(n log n) Without Using Extra MemoryHow heap sort builds a max-heap inside the array itself, why the bottom-up build is O(n) rather than O(n log n), and why quick sort still beats it in practice.18 min
- Counting Sort in Python: Sorting Without Comparing AnythingCounting sort never compares two items. Tally each key, turn the tally into output positions with a prefix sum, place every item — O(n + k), stable, and useless when k is big.22 min
- Radix Sort in Python: Sorting Digit by Digit, Faster Than O(n log n)How sorting one digit at a time beats the comparison bound: why every pass must be stable, why the passes run least significant first, and when it actually wins.14 min
- Timsort: The Algorithm Behind Python's sorted() and list.sort()What Python's sorted() actually runs: natural runs, minrun, binary insertion sort, the merge-stack invariants and galloping mode, with a runnable simplified Timsort.22 min
- Linear Search in Python: The Simplest Algorithm, and When It's Still RightLinear search scans until it finds a match: O(1) at best, exactly n comparisons on a miss, and the only option on unsorted data. Plus the maths for when sorting first pays off.15 min
- Binary Search in Python: Halving the Problem Every StepBinary search halves the range on every probe: the sorted-data precondition, the boundary traps that hang the loop, Python's bisect module, and searching on the answer.22 min
- Arrays and Dynamic Arrays: How Python Lists Actually WorkWhy contiguous memory gives O(1) indexing, how a dynamic array grows, the amortised O(1) append argument done properly, and why insert(0, x) is O(n).17 min
- Linked Lists in Python: Singly, Doubly, and Circular, From ScratchSingly, doubly and circular linked lists built from scratch in Python, with the three-pointer reversal, Floyd's cycle detection, and an honest comparison against list.18 min
- Stacks in Python: Last In, First Out, and Where You Already Use OneA stack is a pile you only ever touch at the top. How push, pop and peek stay constant time on a plain Python list, and the five places you already depend on one.18 min
- Queues and Deques in Python: FIFO, Ring Buffers, and collections.dequeWhy list.pop(0) costs O(n) and what to use instead: a ring buffer built with modulo arithmetic, collections.deque, and the two-stack queue's amortised analysis.13 min
- Hash Tables in Python: How Dictionaries Get O(1) LookupsA dictionary lookup never searches: it computes an index from the key. How hash functions, buckets, collisions, chaining and resizing add up to average O(1).23 min
- Binary Search Trees in Python: Ordered Data That Stays FastThe invariant that makes search cost the height of the tree, insert and all three delete cases in Python, the four traversals, and how sorted input ruins it.19 min
- AVL Trees and Self-Balancing: Fixing the Binary Search Tree's Worst CaseHow an AVL tree stops a binary search tree degenerating into a linked list: balance factors, all four rotations, insert and delete with rebalancing, and the height proof.23 min
- Heaps and Priority Queues in Python: Always Knowing the Smallest ItemHow a binary heap keeps the smallest item one lookup away: the array trick, sift up and sift down from scratch, why building one is O(n), and all of heapq.25 min
- Tries in Python: The Data Structure Behind AutocompleteA trie stores words character by character, so insert, search and prefix queries cost the length of the key and never the number of keys. Built, measured and pruned in Python.23 min
- Union-Find (Disjoint Set) in Python: Tracking Connected Things FastUnion-find built twice: the naive version that degrades to O(n) per query, then union by size and path compression, and what the inverse Ackermann bound really promises.24 min
- Graphs in Python: Adjacency Lists, Matrices, and Which to UseVertices, edges and the vocabulary that goes with them, then adjacency lists, matrices and edge lists compared on memory, lookup cost and traversal speed, with a reusable Python Graph class.20 min
- Breadth-First Search (BFS) in Python: Shortest Paths, Level by LevelBreadth-first search traced by hand: a FIFO queue, level-by-level traversal, shortest paths in unweighted graphs, maze distances, and why you mark nodes on enqueue.19 min
- Depth-First Search (DFS) in Python: Going Deep Before Going WideDepth-first search from first principles: the recursive and iterative forms, why their visit orders differ, pre and post numbering, components, and cycle detection done right.20 min
- Dijkstra's Algorithm in Python: Shortest Paths With Weighted EdgesDijkstra's shortest paths worked through by hand: relaxation, the settled-is-final invariant, a heapq implementation using lazy deletion, and why one negative edge breaks it.20 min
- Bellman-Ford in Python: Shortest Paths When Edges Can Be NegativeWhy V-1 rounds of edge relaxation are exactly the right number, how one extra round proves a negative cycle exists, and how that becomes a currency arbitrage detector.16 min
- Floyd-Warshall in Python: Shortest Paths Between Every Pair of NodesHow three nested loops fill in the shortest route between every pair of vertices, why k has to be the outermost loop, and when running Dijkstra V times is the better call.14 min
- A* Search in Python: Dijkstra With a Sense of DirectionA* is Dijkstra with a heuristic added to the priority: f = g + h. What admissible and consistent mean, what an overestimate costs you, and node expansions counted against Dijkstra.25 min
- Minimum Spanning Trees in Python: Kruskal's and Prim's AlgorithmsKruskal's and Prim's algorithms in Python, with the cut property proved by an exchange argument, both traced on one seven-vertex graph, and the rule for choosing between them.25 min
- Topological Sort in Python: Ordering Tasks That Depend on Each OtherKahn's algorithm and the depth-first variant traced step by step on a real dependency graph, with the free cycle check and where the O(V + E) actually comes from.21 min
- Dynamic Programming Explained: Memoization, Tabulation, and How to Spot ItDynamic programming from the recursion tree up: overlapping subproblems, optimal substructure, memoization versus tabulation, rolling-row space cuts, and a five-step recipe.20 min
- The 0/1 Knapsack Problem in Python: The Classic DP Every Interview UsesThe 0/1 knapsack problem built up from brute force to the rolling array: the take-it-or-leave-it recurrence, the DP table, recovering the chosen items, and why the capacity loop counts down.21 min
- Longest Common Subsequence in Python: How diff Tools WorkThe dynamic programming table behind diff: subsequence versus substring, the two-case recurrence, a grid filled by hand, and the backtrack that recovers the subsequence itself.18 min
- Edit Distance (Levenshtein) in Python: Measuring How Different Two Strings AreHow Levenshtein distance is derived, filled into a table by hand, and read backwards to recover the actual insertions, deletions and substitutions, plus the Damerau variant.14 min
- The Coin Change Problem in Python: Where Greedy Fails and DP WinsTwo problems share one setup: the fewest coins that make an amount, and how many distinct ways make it. Why greedy breaks on coins 1, 3 and 4, and how a table fixes it.21 min
- Greedy Algorithms Explained: When Taking the Best Option Now Actually WorksGreedy algorithms take the best option now and never look back. When that is provably optimal, how the exchange argument proves it, and where the same rule silently fails.17 min
- Huffman Coding in Python: How Compression Actually CompressesHuffman coding built from scratch in Python: why prefix-free codes decode without separators, how the greedy heap merge finds the optimal tree, and what the header really costs.24 min
- Recursion and Backtracking in Python: Building the Mental ModelHow a recursive call actually works, drawn frame by frame on the call stack, then the choose-explore-un-choose pattern that turns recursion into a search over every arrangement.20 min
- The N-Queens Problem in Python: Backtracking at Its ClearestPlacing n queens with none attacking: how one queen per row collapses the search space, why row minus col and row plus col name the diagonals, and what the pruning really costs.20 min
- The KMP Algorithm in Python: String Search Without Ever Going BackwardsHow KMP searches a text without ever re-reading a character: building the LPS border table, the amortised proof of the O(n + m) bound, and when Python's str.find is the better answer.19 min
- Rabin-Karp in Python: Finding Substrings With Rolling HashesRabin-Karp turns every window of the text into one number: the rolling hash arithmetic derived step by step, why a hash match must always be verified, and where it beats KMP.20 min
- The Euclidean Algorithm in Python: The Oldest Algorithm Still in Daily UseEuclid's 2,300-year-old rule for the greatest common divisor: why gcd(a, b) equals gcd(b, a mod b), why it finishes in a handful of divisions, and what the extended version buys you.17 min
- Sieve of Eratosthenes in Python: Every Prime Under a Million, FastCross out multiples instead of testing numbers. Every prime below a million in 2.1 million writes and zero divisions, with the n log log n bound derived rather than asserted.20 min
- Fast Exponentiation in Python: Computing Huge Powers in log n StepsSquare-and-multiply turns n multiplications into about log2(n): the halving identity, recursive and iterative code, modular exponentiation, and Python's three-argument pow.15 min
- The Two Pointers Technique in Python: Turning O(n²) Into O(n)How two indices moving through one list replace a nested loop: the staircase proof behind the sorted pair sum, plus palindromes, in-place compaction, fast and slow, and 3-sum.20 min
- The Sliding Window Technique in Python: Subarray Problems Made LinearFixed and variable sliding windows in Python, with the amortised argument for why a nested while loop is still linear and the precondition that makes shrinking safe.23 min
- Prefix Sums in Python: Answering Range Queries in Constant TimeCompute cumulative totals once and any range sum becomes one subtraction: the n+1 sentinel that kills the off-by-one, 2D rectangles, and difference arrays.22 min
- Building an LRU Cache in Python: The Data Structure Behind Every CacheHow an LRU cache reaches O(1) for lookup, promotion and eviction by pairing a hash map with a doubly linked list, plus the standard library versions you should actually use.23 min