LeetCode 332: Reconstruct Itinerary (Hierholzer + Lexicographical Order)
LeetCode 332Eulerian PathDFSToday we solve LeetCode 332 - Reconstruct Itinerary.
Source: https://leetcode.com/problems/reconstruct-itinerary/
English
Model each ticket as a directed edge. Because every ticket must be used exactly once, this is an Eulerian path problem from JFK.
Use Hierholzer DFS: repeatedly consume the smallest lexicographic outgoing airport, recurse, then append current node on backtracking. Reversing the backtrack order gives the final itinerary with lexical tie-breaking guaranteed.
Time: O(E log E) with heaps/multisets for ordered edge consumption. Space: O(E).
class Solution {
public List<String> findItinerary(List<List<String>> tickets) {
Map<String, PriorityQueue<String>> g = new HashMap<>();
for (List<String> t : tickets) {
g.computeIfAbsent(t.get(0), k -> new PriorityQueue<>()).offer(t.get(1));
}
LinkedList<String> ans = new LinkedList<>();
dfs("JFK", g, ans);
return ans;
}
private void dfs(String u, Map<String, PriorityQueue<String>> g, LinkedList<String> ans) {
PriorityQueue<String> pq = g.get(u);
while (pq != null && !pq.isEmpty()) {
dfs(pq.poll(), g, ans);
}
ans.addFirst(u);
}
}func findItinerary(tickets [][]string) []string {
g := map[string][]string{}
for _, t := range tickets { g[t[0]] = append(g[t[0]], t[1]) }
for k := range g { sort.Strings(g[k]) }
var ans []string
var dfs func(string)
dfs = func(u string) {
for len(g[u]) > 0 {
v := g[u][0]
g[u] = g[u][1:]
dfs(v)
}
ans = append(ans, u)
}
dfs("JFK")
for i, j := 0, len(ans)-1; i < j; i, j = i+1, j-1 { ans[i], ans[j] = ans[j], ans[i] }
return ans
}class Solution {
public:
unordered_map<string, multiset<string>> g;
vector<string> ans;
void dfs(const string& u) {
while (!g[u].empty()) {
auto it = g[u].begin();
string v = *it;
g[u].erase(it);
dfs(v);
}
ans.push_back(u);
}
vector<string> findItinerary(vector<vector<string>>& tickets) {
for (auto &t : tickets) g[t[0]].insert(t[1]);
dfs("JFK");
reverse(ans.begin(), ans.end());
return ans;
}
};from collections import defaultdict
import heapq
from typing import List
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
g = defaultdict(list)
for a, b in tickets:
heapq.heappush(g[a], b)
route = []
def dfs(u: str) -> None:
pq = g[u]
while pq:
dfs(heapq.heappop(pq))
route.append(u)
dfs("JFK")
return route[::-1]var findItinerary = function(tickets) {
const g = new Map();
for (const [a, b] of tickets) {
if (!g.has(a)) g.set(a, []);
g.get(a).push(b);
}
for (const [k, arr] of g) arr.sort();
const ans = [];
function dfs(u) {
const arr = g.get(u) || [];
while (arr.length) dfs(arr.shift());
ans.push(u);
}
dfs('JFK');
return ans.reverse();
};中文
把每张机票看成一条有向边。题目要求每张票恰好使用一次,本质是从 JFK 出发构造欧拉路径。
使用 Hierholzer DFS:每次优先取字典序最小的下一站,走到底后在回溯阶段加入当前机场。最后将回溯结果反转,即得到满足字典序最小要求的完整行程。
时间复杂度:使用有序结构取边时为 O(E log E);空间复杂度 O(E)。
class Solution {
public List<String> findItinerary(List<List<String>> tickets) {
Map<String, PriorityQueue<String>> g = new HashMap<>();
for (List<String> t : tickets) {
g.computeIfAbsent(t.get(0), k -> new PriorityQueue<>()).offer(t.get(1));
}
LinkedList<String> ans = new LinkedList<>();
dfs("JFK", g, ans);
return ans;
}
private void dfs(String u, Map<String, PriorityQueue<String>> g, LinkedList<String> ans) {
PriorityQueue<String> pq = g.get(u);
while (pq != null && !pq.isEmpty()) {
dfs(pq.poll(), g, ans);
}
ans.addFirst(u);
}
}func findItinerary(tickets [][]string) []string {
g := map[string][]string{}
for _, t := range tickets { g[t[0]] = append(g[t[0]], t[1]) }
for k := range g { sort.Strings(g[k]) }
var ans []string
var dfs func(string)
dfs = func(u string) {
for len(g[u]) > 0 {
v := g[u][0]
g[u] = g[u][1:]
dfs(v)
}
ans = append(ans, u)
}
dfs("JFK")
for i, j := 0, len(ans)-1; i < j; i, j = i+1, j-1 { ans[i], ans[j] = ans[j], ans[i] }
return ans
}class Solution {
public:
unordered_map<string, multiset<string>> g;
vector<string> ans;
void dfs(const string& u) {
while (!g[u].empty()) {
auto it = g[u].begin();
string v = *it;
g[u].erase(it);
dfs(v);
}
ans.push_back(u);
}
vector<string> findItinerary(vector<vector<string>>& tickets) {
for (auto &t : tickets) g[t[0]].insert(t[1]);
dfs("JFK");
reverse(ans.begin(), ans.end());
return ans;
}
};from collections import defaultdict
import heapq
from typing import List
class Solution:
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
g = defaultdict(list)
for a, b in tickets:
heapq.heappush(g[a], b)
route = []
def dfs(u: str) -> None:
pq = g[u]
while pq:
dfs(heapq.heappop(pq))
route.append(u)
dfs("JFK")
return route[::-1]var findItinerary = function(tickets) {
const g = new Map();
for (const [a, b] of tickets) {
if (!g.has(a)) g.set(a, []);
g.get(a).push(b);
}
for (const [k, arr] of g) arr.sort();
const ans = [];
function dfs(u) {
const arr = g.get(u) || [];
while (arr.length) dfs(arr.shift());
ans.push(u);
}
dfs('JFK');
return ans.reverse();
};
Comments