InterviewLegend

Core Algorithms

Alex Chen16 min readUpdated 43 real interview reports
In this lesson
  • Practice the graph traversal and hashing work that sits under the crawler and the parsers
  • Write a BFS reachability scan and a hash counter from a blank file, stating the tie rule first
  • Find the planted bug in provided code, and trace a p95 latency spike to a race or leak

The bank is built from systems you build rather than algorithms you recall, and the earlier lessons spend their pages there. A slice of plain algorithm work still survives, though, and it is not the part you would guess. It hides inside the problems you already know. The synchronous core of the web crawler is graph traversal. The tokenizer and the stack-trace profiler run on string handling and hash maps. Almost every problem in the loop ends with the same question about complexity. None of it looks like a fresh medium-hard graph puzzle dropped on you cold, and that is the point worth internalizing before you over-prepare the wrong thing.

So this lesson is narrow on purpose. There is no honest way to frame a binary-search drill or a dynamic-programming grind as Anthropic-specific, because those rarely show up here, and pretending otherwise would waste your prep. Three things do show up. The graph fundamentals the crawler stands on. The string and hashing work the parsers stand on. And the habit of naming a time and space bound out loud, then defending it. Then there is the debugging round, where the algorithm is someone else's and your job is to find what is wrong with it.

The Algorithm Core That Survives

A topic list isn't something Anthropic shares, and the live question bank stays small and stable, so treat the following as the durable core. Graph traversal is non-negotiable. The signature problem is a traversal. Hash maps and sets are everywhere, because dedup and counting are everywhere. Sorting and a clean linear scan cover most of the rest. The exotic single-topic puzzle, the segment tree or the bitmask DP, is not where this loop lives.

The Anthropic angle
Strip the thread pool and the politeness rules off the web crawler and what remains is plain breadth-first search. A queue and a visited set, plus a loop that expands each page's out-links, is the entire synchronous skeleton, and the concurrency follow-up only makes sense once that skeleton is solid. The candidates who stall when the interviewer says make it concurrent are often the ones who were still shaky on the plain traversal underneath, fighting the threads and the graph at the same time. Graph fundamentals are the one classic topic you cannot skip for this loop, precisely because the most-cited live problem is built directly on them. Get BFS and DFS to where you write them without thinking, and the signature round starts from a position of calm.

Graphs: BFS and DFS

The traversal questions arrive in different framings but ask the same thing. Which pages can the crawler reach from the seed. Is there a cycle in the dependency graph the package manager has to resolve. What is the shortest path between two nodes. All of them come down to a queue or a stack, paired with a visited set that stops you from looping forever and a rule for which neighbors to expand. The visited set is the load-bearing piece, and forgetting it on a graph with cycles is the bug that turns a crawl into an infinite loop. The runnable problem below is the crawler's reachability core with the threads removed, so the only thing left to get right is the traversal.

1

Reachable Pages From a Seed

EasyFrequently asked
Problem
This is the synchronous heart of the web crawler, the single most-cited live problem in the Anthropic loop, with the concurrency stripped off so only the graph is left. Pages are numbered 0 to n-1. You are given links, an adjacency list where links[i] is the list of pages that page i links to, and seed, the page the crawl starts from. Return the number of distinct pages reachable from the seed, counting the seed itself.

The graph can contain cycles (page A links to B which links back to A) and duplicate edges (the same out-link listed twice). A visited set has to absorb both, or the crawl never terminates.

count_reachable(links, seed) returns one integer. Every page index in links is in range, and the seed is a valid page.

Input: links = [[1,2],[2],[0],[]], seed = 0

Output: 3

From 0 you reach 1 and 2; from 2 you loop back to 0, already seen. Page 3 is isolated and never reached. Distinct pages: {0,1,2}, so 3.

Input: links = [[1],[2],[3],[]], seed = 0

Output: 4

A straight chain 0 to 1 to 2 to 3 reaches all four pages.

Input: links = [[1,1,1],[]], seed = 0

Output: 2

Page 0 lists page 1 three times. The visited set collapses the duplicate edges, so the count is {0,1} = 2.

How this uses the pattern

Breadth-first or depth-first traversal. Seed a visited set with the start page, expand neighbors, and add each unseen page once. Return the size of the visited set at the end.

Reachable Pages From a Seed

Loading...
Click "Run" to execute your code

Test Cases

Input: [[[1,2],[2],[0],[]], 0]Expected: 3
Input: [[[1],[2],[3],[]], 0]Expected: 4
Input: [[[],[0],[0]], 0]Expected: 1
Input: [[[1,1,1],[]], 0]Expected: 2
Input: [[[0]], 0]Expected: 1
Input: [[[1,2],[3],[3],[]], 0]Expected: 4
The Anthropic angle
This is the crawler with the hard part removed. Drill it. In the live round the interviewer starts you here, watches the traversal come out clean, then layers on the thread pool, asyncio, and the GIL discussion that the concurrency lesson covers. If the synchronous BFS is shaky, the follow-ups have nowhere to stand. Two details earn quiet credit. Mark a page visited when you enqueue it rather than when you dequeue it, so a page never sits in the queue twice. And flag that the visited set is what makes a cyclic graph terminate. Both separate code that runs on the example from code that survives a graph with a loop in it.
Take it further
"Now make it concurrent." This is the load-bearing follow-up, and it is the whole next lesson. A bounded thread pool over the frontier. A lock or a thread-safe structure around the shared visited set, so two workers never crawl the same page. Then per-host politeness, retries with backoff, and a graceful shutdown when the queue drains. A quieter follow-up first, though, is "return the pages in BFS order, nearest first." That one checks whether you actually used a queue and not a stack, because depth-first reaches the same set in a different order. Knowing which traversal you reached for, and why, shows you understand the structure.

Strings and Hashing

The parsing problems run on the other half of the core. The stack-trace profiler keys events by function name. The tokenizer counts how often each token appears and flags the ones outside its vocabulary. The deduplicate-files task hashes content and groups the collisions. Underneath the domain language, these are string handling plus a hash map or a set, and the work is choosing the right key and the right structure. The runnable problem below is the counting core that sits inside a tokenizer, with one detail that always matters in this loop: a deterministic tie rule.

The Anthropic angle
A dictionary and a set carry most of the bank, and pulling in something fancier usually signals the wrong instinct here. Anthropic rewards the simplest approach that holds, one of its seven stated values, and it doubles as a grading lens on the string and counting problems. The visited set in the crawler, the frequency map in the tokenizer and the content hash that dedupes a page against ones already crawled all lean on the same two structures. The candidate who reaches for a trie when a hash map is enough, or hand-rolls a sort when a counter does the job, is solving a harder problem than the one on the table. Pick the plain structure, name its lookup cost, and spend the saved attention on the edge cases instead.
2

Most Frequent Token

EasySometimes asked
Problem
Inside the tokenizer and parsing problems is a counting core: given a stream of tokens, find the one that appears most often. You are given tokens, a list of strings. Return the token with the highest count. If two or more tokens tie for the highest count, return the one that appeared earliest in the list.

The earliest-appearance tie rule is what makes the answer deterministic, the same kind of explicit rule the interviewer expects you to settle before you write the loop.

top_token(tokens) returns one string. The list has at least one token.

Input: tokens = ["the","cat","the","dog","the"]

Output: the

"the" appears three times, more than any other token.

Input: tokens = ["x","y","y","x"]

Output: x

Both "x" and "y" appear twice. The tie goes to the one seen first, "x" at index 0.

Input: tokens = ["b","a","a","b","c"]

Output: b

"a" and "b" each appear twice. "b" first appears at index 0, before "a" at index 1, so "b" wins the tie.

How this uses the pattern

One pass to build a frequency map, plus a record of each token first index. Then pick the token with the highest count, breaking ties by smallest first index.

Most Frequent Token

Loading...
Click "Run" to execute your code

Test Cases

Input: [["a","b","a"]]Expected: "a"
Input: [["x","y","y","x"]]Expected: "x"
Input: [["the","cat","the","dog","the"]]Expected: "the"
Input: [["solo"]]Expected: "solo"
Input: [["b","a","a","b","c"]]Expected: "b"
Input: [["z","z","a","a","a"]]Expected: "a"
The Anthropic angle
Counting with a hash map is the warm-up that the parsing problems are built on, and the whole signal is the tie rule. A frequency map alone gives you the counts, but two tokens can share the top count, and "return any" is not a careful answer. Tracking the first index each token appears at, then breaking ties toward the smaller index, makes the output deterministic and shows you thought about the boundary before the interviewer asked. It is the same discipline the top-spenders ranking and the stack-trace problems reward. State the tie rule up front, then write a comparison that enforces it exactly instead of leaning on whatever order the dictionary happens to iterate in.
Take it further
"Now return the top k tokens, most frequent first." Sort the counted items by count descending and first-index ascending and you have it directly in O(n log n). If k is small against the number of distinct tokens, a heap of size k holds it to O(n log k). That answer signals you have thought about scale. A deeper follow-up covers the unknown-token case. Tokens outside the known vocabulary fold to a single bucket before counting. That is the parsing problem's real-world wrinkle, and a clean thing to raise on your own.

Defending Complexity From Scratch

Whatever the problem, the conversation tends to end in the same place: what is the time and space cost, and can you justify it. For the crawler it is linear in pages plus links. For the token count it is linear in the stream. For a Premium question it is the promise that get and put are both constant time, which is the entire reason the doubly linked list and the hash map sit together. Saying the bound aloud as you write, and naming what dominates it, is treated as part of the answer.

The Anthropic angle
Once your solution runs, the common next move is to take the standard library away and ask you to build the structure underneath it. You solved dedup with a set, so now implement the hash set: the bucket array, the hash, the collision chain, the resize when the load factor climbs. You used an ordered dict for the LRU, so now wire the doubly linked list by hand and explain why that gives constant-time eviction where a plain list would cost linear. This is first-principles reasoning made literal, and it is where the complexity claim gets tested for real, because you cannot defend O(1) lookup on a structure you only know as an import. Drilling the from-scratch versions of the set, the hash map, and the linked list pays off across the whole bank, since the re-implementation request can land on almost any of them.

Two habits make this section go well. Name the dominant term, not just the big-O, so "linear in the number of edges, since every out-link is touched once" beats a bare "O of E." And separate the two costs explicitly. Candidates routinely quote a tight time bound and forget that the visited set or the frequency map is holding the whole input in memory. The next follow-up pushes on exactly that space line. Picture a billion-page crawl and ask where all those pages live.

Debugging and the Incident Round

Some rounds hand you the algorithm and ask what is wrong with it. The code-review variant drops a block of working-looking code, a Premium question or a tokenizer, with a planted bug. It grades how you isolate the fault: read the contract, find the input that violates it, narrow to the line. Reproducing it matters more than fixing it. This is a real and recurring slice of the onsite, so practice it the way you practice writing code.

The Anthropic angle
The incident round hands you a service whose p95 climbed from 100ms to 2000ms and asks you to find why. This is the troubleshooting slot some onsites run. The answer is almost always one of two shapes. A race condition, where two threads touch shared state without a lock. Or a leak, where something held should have been released: a cache that never evicts, a connection pool that never returns. What it really grades is production maturity. Form a hypothesis from the symptom first. A sharp spike points one way, a slow climb points the other. Confirm the hypothesis before you touch code. A speed-focused FAANG loop rarely reaches for this kind of reliability thinking, and a company whose stated work is making systems fail safely will.

Reproduce before you fix

Find the input or the interleaving that triggers the bug before changing a line. A race that only shows under two concurrent writers, a leak that only grows under sustained load. Naming the trigger proves you found the cause rather than a symptom, and it gives you the test that confirms the fix.

Suspect shared state first

When a latency or correctness bug appears only under concurrency, the visited set, the cache, or the counter being mutated without a lock is the usual culprit. The same shared-state instinct that makes the crawler thread-safe is what finds the race in the incident round.

Defend the fix and its cost

A lock fixes the race but can serialize the hot path; an eviction policy fixes the leak but adds bookkeeping. State the tradeoff you are making and the new complexity, the same first-principles defense the algorithm rounds ask for, so the fix stands as a deliberate choice.

Key Takeaways

  • ✓The plain algorithm work that survives this loop is narrow and hides inside the problems you already know. Graph traversal is the synchronous core of the web crawler, and string handling and hash maps are the core of the parsers. There is no honest reason to grind binary search or dynamic programming for an Anthropic SWE loop.
  • ✓Get BFS and DFS reflexive: a queue or stack, a visited set that makes cyclic graphs terminate, marking on enqueue so each node is processed once. The crawler follow-ups have nowhere to stand if the synchronous traversal underneath is shaky.
  • ✓Counting and dedup are a hash map and a set applied cleanly, in line with the Anthropic preference for the simplest approach that works. Settle the tie rule before the loop, name the dominant complexity term, and be ready to re-implement the set, the hash map, or the linked list from scratch when the library is taken away.
  • ✓The debugging and incident rounds grade reproduction over the fix. A p95 spike from 100ms to 2000ms is usually a race on shared state or a leak that never releases. Form a hypothesis from the symptom, confirm it, then defend the fix and its new cost.
Had your Anthropic interview?Tell us what they asked. Reviewed before it goes in, never with your name.
Anthropic interview guide

Know what Anthropic asks before you walk in.

11 coding · 5 system design · 14 behavioral questions

Get Premium$49 a year · 30-day money-back guarantee
Or start freeNo card.

Get their questions first.

InterviewLegend is independent and not affiliated with or endorsed by any company it covers.