Tema: algorithms
-
Dependency order with graph traversal: BFS, DFS and topological sort
Model dependencies as a directed graph, use breadth-first or depth-first traversal to find everything affected by a change, and Kahn's algorithm or DFS post-order to produce a build or migration order that reports cycles instead of hiding them; graphlib and tsort implement the sort.
-
Hash tables in practice: collisions, load factor and seeded hashing
A hash table is fast on average only while keys spread evenly over buckets; collisions, the load factor that triggers rehashing, and per-process hash seeding against hash flooding decide its real behaviour. Never persist hash values or rely on iteration order.
-
Dynamic programming step by step: deriving edit distance
Dynamic programming turns a recursive definition with overlapping subproblems into a polynomial algorithm: define the state, write the recurrence and base cases, memoise or fill a table, then cut memory. Edit distance between two strings is derived in full as the worked example.
-
Recursion versus iteration: stack depth, limits and when to convert
Recursion mirrors tree-shaped problems but spends one stack frame per level; the stack is bounded by the interpreter's recursion limit or the thread's stack size, so recursion over input-controlled depth is a crash waiting to happen. Convert to an explicit stack or loop when depth grows with input size.
-
Reservoir sampling: a uniform sample from a stream of unknown length
Keep k items from a stream without knowing its length: fill the reservoir with the first k, then replace a random slot with probability k/i for item i. One pass, O(k) memory, every item ends up in the sample with probability exactly k/n, shown by a short telescoping argument.
-
Tries for prefix lookups: autocomplete and longest-prefix matching
A trie stores strings with one node per common prefix, so lookup costs the key length regardless of how many keys exist, all keys with a prefix form one subtree, and the longest stored prefix of a query is found in one walk; use it for autocomplete and routing, and compare against a sorted array first.
-
Binary search pitfalls: midpoint overflow and off-by-one boundaries
Binary search is short and famously easy to get wrong: the midpoint (low + high) / 2 overflows fixed-width integers, inclusive and exclusive bounds get mixed, and duplicates raise the question of which index to return. Use a library or the monotone-predicate form with half-open intervals, and test the edges.
-
Reasoning about complexity before optimising
Asymptotic complexity predicts how run time grows with input size; recognising quadratic loops, repeated linear searches and unbounded recursion in code review prevents most performance incidents before profiling is needed.
-
Token bucket, leaky bucket and sliding window: how rate-limiter algorithms differ
Fixed windows are cheap but let twice the limit through at a boundary; sliding logs are exact but store every timestamp; sliding-window counters approximate in constant memory; token buckets allow bursts up to the bucket size at a fixed refill rate; leaky buckets smooth output by delaying. nginx and Envoy document the last two.
-
Bloom filters: probabilistic set membership with no false negatives
A Bloom filter answers 'definitely not in the set' or 'probably in the set' with a small bit array and k hash functions; false positives are tunable, false negatives impossible, deletion unsupported. Use it to skip lookups for absent keys, and always verify a positive against the source of truth.
-
Use a token bucket for tool calls
Implement bounded bursts with an explicit token refill equation, atomic consumption and a separate limit on in-flight requests.
-
Sorting stability: what it guarantees and when it matters
A stable sort keeps the input order of elements that compare equal. Python guarantees it, ECMAScript has required it since 2019, Go and GNU sort offer it as an option; it decides whether multi-key sorts, sortable tables and paginated queries behave predictably.
Legível por máquina: JSON