Graphs that are never built

Graphs

Graphs that are never built

The nodes are states and the edges are moves. Nothing is stored; the neighbors are computed on demand.

Key idea

The graph is implied by the rules

Not every graph arrives as a list of edges. Often the problem describes states and legal moves between them, and the graph exists only in the sense that the rules define it.

Breadth-first search does not care. It needs a starting state, a way to recognize the goal, and a function producing the neighbors of a state. Where those neighbors come from is irrelevant to the search.

Why it works

The visited set is what makes it finite

The state space here is bounded by the limit, and without the seen set the search would revisit states endlessly and never terminate on any input with a cycle.

In an implicit graph the visited set is doing more work than in an explicit one: it is the only thing preventing the search from exploring an infinite space. Adding a state when it is queued, rather than when it is dequeued, also stops the same state being queued many times before its first processing.

Key idea

Generating neighbors efficiently

The expensive part is usually producing the neighbors. Comparing the current state against every other candidate state is the obvious approach and it costs the whole state space per step.

The alternative is to generate the neighbors directly from the state by applying each legal transformation. For string problems that means changing one position at a time to each possible character, which costs the string length times the alphabet size rather than the dictionary size.

Position 0 finds dot and lot, position 1 finds hit, position 2 finds hog. cog differs in two places and is not a neighbor

Tip

The wildcard-bucket alternative

There is a third approach: pre-group every word under each of its one-character-removed patterns, so hot lands in buckets *ot, h*t, and ho*. Two words are neighbors exactly when they share a bucket.

That costs one pass over the dictionary up front and makes each neighbor lookup a few dictionary reads. When the alphabet is large or words are long it is much better than trying every letter.

Which to use depends on the sizes involved. Naming both and saying which you would pick for the stated constraints is the strongest answer.

Key idea

Searching from both ends

When both the start and the goal are known, running two searches toward each other and stopping when they meet explores far fewer states, because two small wavefronts are cheaper than one large one.

It is a genuine optimization and adds real complexity: two frontiers, two visited sets, and care about which side to expand next. Mention it; implement it only if asked.

Cost

Cost

The search visits each reachable state once, so the time is the number of states times the cost of generating one state's neighbors.

That second factor is the part people omit. For the string version it is the word length times the alphabet size times the cost of a set lookup, and quoting the whole product rather than just the state count is what a complexity question is checking.

Predict the output: generating neighbors instead of storing them

The graph is never built. A word's neighbors are produced on demand by changing one character at a time and keeping whatever the dictionary contains. Type the two lines it prints.

Word Ladder

Read the constraints first and let them tell you what complexity is expected. Derive the approach, implement it, run the tests, and submit when it passes.

Loading the workspace…
← Previous