Problem Statement
You are given a list of airline tickets where tickets[i] = [fromi, toi] represent the departure and the arrival airports of one flight. Reconstruct the itinerary in order and return it.
All of the tickets belong to a man who departs from “JFK”, thus, the itinerary must begin with “JFK”. If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string.
For example, the itinerary [“JFK”, “LGA”] has a smaller lexical order than [“JFK”, “LGB”].
You may assume all tickets form at least one valid itinerary. You must use all the tickets once and only once.
Example 1:
Input: tickets = [[“MUC”,”LHR”],[“JFK”,”MUC”],[“SFO”,”SJC”],[“LHR”,”SFO”]]
Output: [“JFK”,”MUC”,”LHR”,”SFO”,”SJC”]
Example 2:
Input: tickets = [[“JFK”,”SFO”],[“JFK”,”ATL”],[“SFO”,”ATL”],[“ATL”,”JFK”],[“ATL”,”SFO”]]
Output: [“JFK”,”ATL”,”JFK”,”SFO”,”ATL”,”SFO”]
Explanation: Another possible reconstruction is [“JFK”,”SFO”,”ATL”,”JFK”,”ATL”,”SFO”] but it is larger in lexical order.
Constraints:
1 <= tickets.length <= 300tickets[i].length == 2tickets[i].length == 2toi.length == 3fromiandtoiconsist of uppercase English letters.fromi != toi
Approach
- Build Graph:
- Create an adjacency list where each airport maps to a list of destination airports.
- Sort Destinations:
- For every airport, sort its destination list lexicographically because we must always choose the smallest possible next airport.
- Depth-First Search (DFS):
- Use DFS starting from "JFK"
- Always pick the lexicographically smallest unused ticket (shift from the list).
- Recursively visit that next airport.
- When an airport has no more outgoing edges, add it to the path.
- Use DFS starting from "JFK"
- Reverse Path:
- The final itinerary builds in reverse order because nodes are added after exploring all edges, so reverse it before returning.
Dry Run
Input:
tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
Graph Construction: JFK → [MUC] MUC → [LHR] LHR → [SFO] SFO → [SJC] All adjacency lists sorted (already sorted here).
Initialize: path = [ ] Start DFS: dfs("JFK") dfs("JFK")
• neighbors = ["MUC"] • take "MUC" → dfs("MUC") dfs("MUC")
• neighbors = ["LHR"] • take "LHR" → dfs("LHR") dfs("LHR")
• neighbors = ["SFO"] • take "SFO" → dfs("SFO") dfs("SFO")
• neighbors = ["SJC"] • take "SJC" → dfs("SJC") dfs("SJC")
• graph["SJC"] is empty • push "SJC" → path = ["SJC"] (return) Back to dfs("SFO")
• no neighbors left • push "SFO" → path = ["SJC","SFO"] Back to dfs("LHR")
• no neighbors left • push "LHR" → path = ["SJC","SFO","LHR"] Back to dfs("MUC")
• no neighbors left • push "MUC" → path = ["SJC","SFO","LHR","MUC"] Back to dfs("JFK")
• no neighbors left • push "JFK" → path = ["SJC","SFO","LHR","MUC","JFK"]
Final step: Reverse path → ["JFK","MUC","LHR","SFO","SJC"] Output:
["JFK","MUC","LHR","SFO","SJC"]
var findItinerary = function(tickets) {
let graph = {};
for (let [from, to] of tickets) {
if (!graph[from]) graph[from] = [];
graph[from].push(to);
}
for (let node in graph) {
graph[node].sort(); // ascending lexicographic
}
let path = [];
let dfs = (curr) => {
while (graph[curr] && graph[curr].length) {
let neighbor = graph[curr].shift(); // remove from front
dfs(neighbor);
}
path.push(curr);
};
dfs("JFK");
return path.reverse(); // reverse before returning
};
from collections import defaultdict, deque
from typing import List
def findItinerary(tickets: List[List[str]]) -> List[str]:
graph = defaultdict(list)
for frm, to in tickets:
graph[frm].append(to)
# sort and convert to deque for efficient popleft
for k in graph:
graph[k].sort()
graph[k] = deque(graph[k])
path = []
def dfs(curr: str):
dest = graph.get(curr, deque())
while dest:
nxt = dest.popleft()
dfs(nxt)
path.append(curr)
dfs("JFK")
return path[::-1]
import java.util.*;
public class Solution {
public List findItinerary(List> tickets) {
Map> graph = new HashMap<>();
for (List t : tickets) {
graph.computeIfAbsent(t.get(0), k -> new LinkedList<>()).add(t.get(1));
}
// sort each adjacency list and turn into a LinkedList (so we can removeFirst)
for (Map.Entry> e : graph.entrySet()) {
List list = e.getValue();
Collections.sort(list);
e.setValue(new LinkedList<>(list));
}
List path = new ArrayList<>();
dfs("JFK", graph, path);
Collections.reverse(path);
return path;
}
private void dfs(String curr, Map> graph, List path) {
LinkedList dest = graph.get(curr);
while (dest != null && !dest.isEmpty()) {
String next = dest.removeFirst();
dfs(next, graph, path);
}
path.add(curr);
}
}
#include <bits/stdc++.h>
using namespace std;
vector findItinerary(vector>& tickets) {
unordered_map> graph;
for (auto &t : tickets) {
graph[t[0]].push_back(t[1]);
}
// sort destinations lexicographically ascending
for (auto &p : graph) sort(p.second.begin(), p.second.end());
vector path;
function dfs = [&](const string &curr) {
auto &dest = graph[curr];
while (!dest.empty()) {
string next = dest.front();
dest.erase(dest.begin()); // remove from front
dfs(next);
}
path.push_back(curr);
};
dfs("JFK");
reverse(path.begin(), path.end());
return path;
}
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_NODES 1000
#define MAX_TICKETS 10000
#define MAX_STR_LEN 64
// adjacency list storage
char *adj[MAX_NODES][MAX_TICKETS];
int adjCount[MAX_NODES];
char nodes[MAX_NODES][MAX_STR_LEN];
int nodeCount = 0;
int find_or_add_node(const char *s) {
for (int i = 0; i < nodeCount; ++i)
if (strcmp(nodes[i], s) == 0) return i;
if (nodeCount >= MAX_NODES) { fprintf(stderr, "node limit\n"); exit(1); }
strncpy(nodes[nodeCount], s, MAX_STR_LEN-1);
nodes[nodeCount][MAX_STR_LEN-1] = '\0';
adjCount[nodeCount] = 0;
return nodeCount++;
}
int cmp_strptr(const void *a, const void *b) {
const char *const *pa = a;
const char *const *pb = b;
return strcmp(*pa, *pb);
}
char *path[MAX_TICKETS + MAX_NODES];
int pathLen = 0;
void dfs(int u) {
while (adjCount[u] > 0) {
// pop front: take adj[u][0], then shift remaining left
char *next = adj[u][0];
// shift left
for (int i = 1; i < adjCount[u]; ++i)
adj[u][i-1] = adj[u][i];
adjCount[u]--;
// find index of next node
int v = -1;
for (int i = 0; i < nodeCount; ++i)
if (strcmp(nodes[i], next) == 0) { v = i; break; }
if (v == -1) { fprintf(stderr, "node not found\n"); exit(1); }
dfs(v);
}
path[pathLen++] = strdup(nodes[u]);
}
int main() {
// Example input: you can replace this with dynamic input parsing.
// Here we hardcode a few tickets for demonstration.
const char *tickets[][2] = {
{"MUC","LHR"},
{"JFK","MUC"},
{"SFO","SJC"},
{"LHR","SFO"}
};
int ticketCount = 4;
// build graph
for (int i = 0; i < ticketCount; ++i) {
int a = find_or_add_node(tickets[i][0]);
int b = find_or_add_node(tickets[i][1]);
adj[a][adjCount[a]++] = strdup(tickets[i][1]);
}
// sort adjacency lists lexicographically
for (int i = 0; i < nodeCount; ++i) {
if (adjCount[i] > 0) {
qsort(adj[i], adjCount[i], sizeof(char*), cmp_strptr);
}
}
// find index of "JFK"
int start = -1;
for (int i = 0; i < nodeCount; ++i) {
if (strcmp(nodes[i], "JFK") == 0) { start = i; break; }
}
if (start == -1) {
printf("No JFK start\n");
return 0;
}
dfs(start);
// reverse and print
for (int i = pathLen - 1; i >= 0; --i) {
printf("%s", path[i]);
if (i) printf(" -> ");
}
printf("\n");
for (int i = 0; i < pathLen; ++i) free(path[i]);
for (int i = 0; i < nodeCount; ++i)
for (int j = 0; j < adjCount[i]; ++j)
free(adj[i][j]);
return 0;
}
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public IList FindItinerary(IList> tickets) {
var graph = new Dictionary>();
foreach (var t in tickets) {
var from = t[0];
var to = t[1];
if (!graph.ContainsKey(from)) graph[from] = new LinkedList();
graph[from].AddLast(to);
}
// sort each adjacency list lexicographically
var keys = graph.Keys.ToList();
foreach (var k in keys) {
var sorted = graph[k].OrderBy(s => s).ToList();
graph[k] = new LinkedList(sorted);
}
var path = new List();
Dfs("JFK", graph, path);
path.Reverse();
return path;
}
private void Dfs(string curr, Dictionary> graph, List path) {
if (!graph.ContainsKey(curr)) {
path.Add(curr);
return;
}
var dest = graph[curr];
while (dest.Count > 0) {
var next = dest.First.Value;
dest.RemoveFirst();
Dfs(next, graph, path);
}
path.Add(curr);
}
}
