
Delve into advanced algorithms and data structures in Python, including binary trees, splay and ternary search trees, external memory, substring search, and optimization problems like traveling salesman and Chinese postman.
Fenwick trees, or binary index trees, use binary indices to compute prefix sums and updates efficiently, delivering logarithmic time queries with 1-based indexing.
Construct a Fenwick tree from a one-dimensional array using binary index representations and a zero-based root; flipping the rightmost 1 reveals a parent and array size equals original plus one.
Fenwick trees theory explains computing prefix sums and updates with binary indices, showing how to find parent nodes and propagate changes for simple implementation.
Implement a Fenwick tree as a one-dimensional array with a root at index zero, initialize with zeros, and build update and sum operations by navigating parent nodes in logarithmic time.
Explore fenwick trees implementation II by performing updates, computing prefix sums, and querying interval sums in logarithmic time through index-based updates and the prefix sum method.
Explore why caches use least recently used strategies to achieve constant-time insertions and lookups with hash tables and doubly linked lists.
Explore how an LRU cache uses a doubly linked list and a hash table to achieve constant-time insertion, lookup, and removal of least recently used items.
implement an lru cache with a doubly linked list and a dictionary to achieve constant-time lookups. move accessed items to the head and evict the tail to respect capacity.
learn LRU cache implementation in Python using a doubly linked list and a dictionary to provide constant-time get and update operations, with head and tail management.
Implement an LRU cache with a doubly linked list and a dictionary, storing up to four websites and evicting the least recently used item, and preview the display tree later.
Explore splay trees, a binary search tree variant where recently accessed items rise to the root via rotations, enabling amortized logarithmic access with linear worst-case for caches and lookups.
Explore splay trees and their rotations by walking through a concrete search example; learn how zig-zag rotations bring an item like 12 to the root, improving access speed.
This lecture explains splay trees by implementing a binary search tree with splaying to keep recently accessed items near the root, enabling constant running time access.
Implement left and right rotations in splay trees, update child and parent references precisely, and relate these rotations to AVL and red-black trees for correct subtree reorganization.
Implement the splay tree display operation by rotating a given node to the root, handling zig-zig and zig-zag cases. The approach supports searching, inserting, and caching recently visited items.
Explore how splay trees power caches, garbage collectors, and IP routing tables by keeping recently accessed items near the root for fast access.
Explore the contrast between main memory (RAM) and external memory (hdd), including speed differences, data transfer from external to main memory, and the use of 512-byte blocks.
External memory access is much slower than main memory, so data structures must minimize reads and leverage 512-byte blocks, as with the B3 design.
Explore how B-trees store multiple keys and children to optimize external memory access, delivering logarithmic time for insertion, removal, search, and sequential access in databases and file systems.
Explore insertion in a two-three B-tree, promote the middle value to the root, manage node capacity and references, and trace search paths.
Learn how to delete items from a B-tree (B3), handling simple deletions, underflow corrections with left or right rotations, and merge operations to maintain B-tree properties.
Examine B-tree variants like star trees and B+ trees, focusing on external memory efficiency and fuller nodes for faster searches in file systems.
Explore trie data structures, or prefix trees, where keys are strings and edges denote letters to implement associative arrays, and note speed versus memory trade-offs.
Understand how a prefix tree (trie) inserts and searches words by letters, with a root representing the empty string. Compare its sublinear search to hash tables.
Explore how a trie enables sorting by performing an in order traversal, visiting left subtrees, the root (empty string), then right subtrees to output words in alphabetical order.
Explore how a trie enables fast autocomplete by prefix querying and collecting words via in-order traversal. Implement the autocomplete problem from scratch, demonstrating practical applications like Google search suggestions.
Explore how prefix trees (tries) implement associative arrays by storing key-value pairs as leaf data, using sequential character traversal for inserts and lookups, and compare with hash-based methods.
Describe a trie implementation with 26-branch nodes, root initialization, and word insertion by walking or creating children using ASCII indexing; explain leaf nodes and memory costs.
Implement and explore trie-based autocomplete and sorting by prefix, using a root node, ascii index-based child lookup, and in-order traversal to collect words; discuss memory trade-offs of prefix trees.
Transform the trie into an associative array by storing key-value pairs at leaf nodes. Iterate through key characters, create needed nodes, and assign the leaf value.
Compare hashing-based associative arrays and trie data structures, highlighting search efficiency, collision effects, and memory layout, including external memory considerations and the trade-offs between hash tables and tries.
Explore applications of trie data structures, including Google search autocomplete, spell checkers, IP routing with longest common prefixes, and ternary tries for memory efficiency, then compare with hashing.
Discover how longest common prefix search with trie data structures enables efficient IP routing, guiding packets using IP addresses toward the destination to compute the shortest path in networks.
This lecture uses a trie data structure to solve the longest common prefix problem with an alphabet of 128 and ascii indices, building the prefix by traversing single-child nodes.
Explore ternary search trees, a memory-efficient alternative to tries, with three children per node and characters and values stored in nodes, balancing memory use and speed.
Visualize inserting and searching keys in a ternary search tree, where nodes have left, middle, and right children and leaf nodes store key-value pairs, forming an associative array.
Implement a ternary search tree by creating a node with a character and left, middle, and right children, and expose recursive put and get methods for key-value storage.
Visualize a recursive insertion into a ternary structure, tracing stack memory, key and value, and index-driven navigation through left and middle branches with backtracking to place a new pair.
Implement the get function in a ternary search tree to retrieve a key's value by traversing left, middle, and right nodes according to each character.
Implement an in-order traversal of a ternary search tree in Python, visiting left subtree, middle (updating the key), and right subtree to print key and value pairs.
Explore how boggle uses a 3 by 3 letter grid to form valid words, validating sequences with a trie (or ternary search) and backtracking through four-neighbor paths to maximize words.
Explore the concrete implementation of a boggle game using a ternary search tree to validate words, including copying code, inserting words, and backtracking with a 3x3 board and visited tracking.
Extend a boggle game with bounds checks, visited tracking, and backtracking to form valid words using a ternary search tree.
Apply a backtracking boggle game with a ternary search tree to verify words in a grid, test word dog and computer, and explore diagonal versus four-neighbor traversal.
Explore the brute-force substring search algorithm, testing the pattern against the text, handling mismatches by shifting the pattern, and understanding its worst-case complexity.
Implement the naive brute-force substring search by aligning the pattern with the text, comparing characters, shifting one position on a mismatch, and reporting matches, with understanding of its inefficiency.
Explore the Rabin-Karp algorithm for efficient substring search using hashing and rolling hashes. Learn how polynomial fingerprint functions reduce false matches and enable linear time performance.
Implement the Rabin-Karp algorithm in Python by building a fingerprinting function, computing rolling hashes, and sliding the pattern over the text to find matches.
Knuth-Morris-Pratt algorithm pre-processes the pattern into a partial match (pie) table to achieve linear-time substring search by avoiding redundant comparisons.
Visualize constructing the partial match table for the Knute Morris algorithm, showing how to update the prefix counter and table as the pattern is scanned.
Implement the Knuth-Morris-Pratt algorithm by building the partial match (pie) table and performing a text search to find the pattern in linear time.
Explore the Z algorithm for substring search, building the Z table and Z boxes to locate pattern occurrences in text with linear time, via concatenated pattern and text.
Explore the z algorithm through a concrete example, updating z values and z boxes with left and right indices to efficiently find pattern matches in text.
Implement the Z algorithm from scratch in Python, building a Z table for the pattern and text, and locate all pattern occurrences in linear time.
Compare substring search algorithms like brute force search, Boyer-Moore, KMP, and the rating corp algorithm, highlighting their advantages and disadvantages and suitability for long patterns or small alphabets.
Explore how substring search finds and replaces patterns in software like Eclipse, and why it underpins bioinformatics tasks such as DNA sequence analysis using linear-time algorithms.
This course is for those who are interested in computer science and want to implement the algorithms and given data structures in Python. In every chapter you will learn about the theory of a given data structure or algorithm and then you will implement them from scratch.
Chapter 1: Binary Indexed Trees (Fenwick Trees)
theory behind the binary indexed tree or Fenwick tree data structure
how to use this data structure in computer vision and artificial intelligence
implementation in Python
Chapter 2: LRU Caches
what are caches and why are they so important
how to use doubly linked lists to implement caches
theory behind LRU caches
implementation in Python
Chapter 3: Splay Trees
what are splay trees
how to achieve caches with splay trees
Chapter 4: B-Trees
external memory and internal memory (RAM)
data structures for the external memory
trees with multiple children and multiple keys
what are B-tree data structures?
Chapter 5: Prefix Trees (Tries)
what are tries or prefix trees
real world applications of tries
autocomplete feature of tries
sorting with tries
IP routing
Chapter 6: Ternary Search Trees
what are ternary search trees
boggle game with tries
Chapter 7: Substring Search Algorithms
what are substring search algorithms and why are they important in real world softwares
brute-force substring search algorithm
hashing and Rabin-Karp method
Knuth-Morris-Pratt substring search algorithm
Z substring search algorithm (Z algorithm)
implementations in Python
Chapter 8: Topological Ordering
what is topological ordering (topological sort)?
topological ordering implementation with depth-first search
Chapter 9: Cycle Detection
how to detect cycles in graphs?
Chapter 10: Strongly Connected Components (Tarjan's Algorithm)
what are strongly connected components?
Tarjan's algorithm with depth-first search
Chapter 11: Hamiltonian cycles (Travelling Salesman Problem)
Hamiltonian cycles in graphs
what is the travelling salesman problem?
how to use backtracking to solve the problem
meta-heuristic approaches to boost algorithms
Chapter 12: Eulerian Cycles (Chinese Postman Problem)
Eulerian cycles in graphs
what is the chinese postman problem?
Thanks for joining my course, let's get started!