Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

Coding Interview Patterns  Module 20 – Graph patterns: traversal

Reconstruct an itinerary with Eulerian paths

Rebuild a trip that used every ticket exactly once, alphabetically first when several exist, with the brute force over every order and the signal to notice.

  • Advanced
  • 35 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0, quickjs 0.32.0, Java 25, Clang 21.0.0 and Go 1.27.1
  • By MySmartCoPilot
Free intro, Pro: 7 of 35 minutes free
Free: The problem: a trip rebuilt from its ticket stubs · The brute force, and why it fails at these sizes · What to notice. With a pass: the other 14 sections and 3 interview answers, about 28 minutes.

What you will learn

  • Check the in and out counts that decide whether a path using every edge once exists, and where it ends
  • Build the path with Hierholzer's algorithm and an explicit stack
  • Find the alphabetically first itinerary by taking each station's tickets in sorted order
  • Prove that the result uses every edge once and that no earlier itinerary exists
  • Test an itinerary builder against a backtracking search on every small ticket set

Before you start

What you’ll learn · Before you start

What you will learn

  • Check the in and out counts that decide whether a path using every edge once exists, and where it ends
  • Build the path with Hierholzer's algorithm and an explicit stack
  • Find the alphabetically first itinerary by taking each station's tickets in sorted order
  • Prove that the result uses every edge once and that no earlier itinerary exists
  • Test an itinerary builder against a backtracking search on every small ticket set

Before you start

On this page

To reconstruct an itinerary from a pile of used tickets is to find an Eulerian path: a route through a graph that uses every edge exactly once. Stations are the nodes and tickets the directed edges. Such a route exists only when every station has as many tickets in as out, except that the start may have one more out and the end one more in. Hierholzer’s algorithm then builds the route in linear time, and taking each station’s alphabetically smallest ticket first makes it the alphabetically first itinerary.

The problem: a trip rebuilt from its ticket stubs

A traveller kept the stub of every ticket of a rail trip. Each stub names the station the leg left from and the station it reached, as three-letter codes. The trip began at a known station and used every ticket exactly once. Rebuild the stations in order. When several orders are possible, return the one that comes first alphabetically, comparing station by station. A trip always exists, and the same ticket may appear twice. Limits: 1 to 10,000 tickets.

  1. AMB → BRK, BRK → CAS, CAS → AMB, AMB → DAL from AMB gives AMB BRK CAS AMB DAL.
  2. AMB → BRK, AMB → CAS, CAS → AMB from AMB gives AMB CAS AMB BRK, although BRK comes before CAS.
  3. AMB → BRK, BRK → AMB, AMB → BRK from AMB gives AMB BRK AMB BRK: the repeated ticket is used twice.
Two ticket graphs: four tickets that form one trip from AMB, and three tickets where the smallest ticket from AMB must be used last.Example 1: four ticketsExample 2: a dead endAMBBRKCASDALAMBBRK, the endCAS12343: last12

The first two examples as graphs of stations and tickets

Text description of the diagram

Each box is a station and each arrow a ticket, from the station it starts at to the station it goes to. The number on an arrow is that ticket's place in the answer.

The upper panel shows example 1: arrows from AMB to BRK (1), BRK to CAS (2), CAS back to AMB (3) and AMB to DAL (4). Following the numbers gives the trip AMB, BRK, CAS, AMB, DAL, which uses every ticket once.

The lower panel shows example 2: arrows from AMB to CAS (1), CAS back to AMB (2), and a dashed arrow from AMB to BRK labelled "3: last". BRK is labelled as the end of the trip. The ticket to BRK is the alphabetically smallest one out of AMB, but BRK has no ticket out, so taking it first would end the trip with two tickets unused. The trip is AMB, CAS, AMB, BRK.

The brute force, and why it fails at these sizes

Try every order of the tickets, keep the orders in which each leg starts where the one before it ended, and return the alphabetically first trip among them.

Every order of the tickets, with the count Python · brute/brute_force.py
"""The brute force: every order of the tickets, keeping the alphabetically first one that makes a trip. The work is
counted, not timed, so every computer prints the same."""
from itertools import permutations


def first_trip(tickets, start):
    tried, best = 0, None
    for order in permutations(tickets):
        tried += 1
        here, stations = start, [start]
        for a, b in order:
            if a != here:
                break
            stations.append(b)
            here = b
        else:  # every ticket was used, each leg starting where the last one ended
            best = stations if best is None else min(best, stations)
    return best, tried


print("example 1:", " ".join(first_trip([("AMB", "BRK"), ("BRK", "CAS"), ("CAS", "AMB"), ("AMB", "DAL")], "AMB")[0]))
print("example 2:", " ".join(first_trip([("AMB", "BRK"), ("AMB", "CAS"), ("CAS", "AMB")], "AMB")[0]))
print("example 3:", " ".join(first_trip([("AMB", "BRK"), ("BRK", "AMB"), ("AMB", "BRK")], "AMB")[0]))
print("tickets   orders tried")
for n in (6, 7, 8):
    loop = [(f"S{i}", f"S{(i + 1) % n}") for i in range(n)]  # one round trip through n stations
    print(f"{n:>7}   {first_trip(loop, 'S0')[1]:>12,}")
print("one more ticket multiplies the orders: 10 give 3,628,800, 20 about 2.4 x 10^18, 10,000 a number of 35,660 digits")

Output

example 1: AMB BRK CAS AMB DAL
example 2: AMB CAS AMB BRK
example 3: AMB BRK AMB BRK
tickets   orders tried
      6            720
      7          5,040
      8         40,320
one more ticket multiplies the orders: 10 give 3,628,800, 20 about 2.4 x 10^18, 10,000 a number of 35,660 digits

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 brute_force.py

It is right on the examples, but n tickets have n! orders: 40,320 for 8 tickets, 3,628,800 for 10, and for 10,000 tickets a number with 35,660 digits. Most of those orders break at the first leg, and still the count alone rules the method out.

What to notice

  • It is a graph problem. A trip that uses every ticket once is a path that uses every edge once.
  • Counting decides where it ends. A station the trip passes through is left as often as it is entered, so only the start can have an extra ticket out and only the end an extra ticket in.
  • The smallest ticket is not always the next leg. In example 2, AMB → BRK leads to the station where the trip must end, so it has to be used last.

Four techniques follow from these signals, and two variants use them:

  • Degree counting compares tickets in and out of every station, to check that a trip exists and where it ends.
  • Hierholzer’s algorithm walks along unused tickets and writes a station down once it has no ticket left.
  • Sorted ticket lists make the trip it builds the alphabetically first one.
  • An explicit stack replaces the recursion, so 10,000 tickets in a row need no deep call stack.
  • The variants walk two-way streets with numbered edges and build the shortest string that holds every lock code.

When a trip exists: tickets in and out Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Hierholzer’s algorithm with a stack, step by step
  • Why it uses every ticket exactly once
  • Why smallest first gives the alphabetically first trip
  • A dry run on the dead end
  • The code in five languages
  • How much work it does
  • Edge cases and common bugs
  • Variants: streets both ways and a keypad lock
  • Follow-up questions
  • Exercise: rebuild the alphabetically first trip
    • Rebuild the alphabetically first trip from ticket stubs
  • A practice set with sample answers
  • Check yourself
  • Interview questions
    • What must the tickets in and out of each station look like for a trip that uses every ticket once to exist, and where must that trip start?
    • Your itinerary code always takes the alphabetically smallest unused ticket out of the current station. It passes the samples but returns a trip that leaves tickets unused on a hidden test. Give an input that breaks it, and fix the code without losing the alphabetical order.
    • A street-cleaning vehicle must drive along every one of a town's 3,000 two-way streets at least once and return to its depot. When can it drive each street exactly once, and what do you compute when it cannot?
    • A sync service receives 1,000,000 overlapping 3-character chunks of a log, where each chunk shares its last 2 characters with the first 2 of the next one. Rebuild a log that uses every chunk exactly once. How do you model it, how fast is it, and when is the answer ambiguous?
  • Key takeaways

5 runnable examples (C++, Go, Java, JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 24 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.