Hard

Reconstruct Itinerary

Description

Use every directed flight ticket exactly once to build an itinerary beginning at JFK. If multiple complete itineraries exist, return the lexicographically smallest. Assume a valid itinerary exists; duplicate tickets represent separate flights.

Solution

def find_itinerary(tickets):
    flights = {}
    for source, target in tickets:
        flights.setdefault(source, []).append(target)
    for destinations in flights.values():
        destinations.sort(reverse=True)
    stack, route = ["JFK"], []
    while stack:
        destinations = flights.get(stack[-1], [])
        if destinations:
            stack.append(destinations.pop())
        else:
            route.append(stack.pop())
    return route[::-1]

Examples

Example 1

Input
[[["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]]
Output
["JFK","MUC","LHR","SFO","SJC"]

The flights form a single chain.

Example 2

Input
[[["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]]]
Output
["JFK","NRT","JFK","KUL"]

KUL is a dead end and must be visited last.

Example 3

Input
[[["JFK","A"]]]
Output
["JFK","A"]

Use the sole ticket.

Approach

Sort each airport's destinations in reverse lexical order and remove the smallest from the end. Follow flights with a stack; when an airport has no unused outgoing ticket, append it to a reverse route. Reversing that route completes Hierholzer's Eulerian-path construction.

Time & space

O(E log E) time and O(E) auxiliary space, where E is ticket count.