diff --git a/solution/0300-0399/0332.Reconstruct Itinerary/README.md b/solution/0300-0399/0332.Reconstruct Itinerary/README.md index f14fd8ac83b8b..09f9bbbeb93b4 100644 --- a/solution/0300-0399/0332.Reconstruct Itinerary/README.md +++ b/solution/0300-0399/0332.Reconstruct Itinerary/README.md @@ -64,7 +64,13 @@ tags: -### 方法一 +### 方法一:欧拉路径 + +题目实际上是给定 $n$ 个点和 $m$ 条边,要求从指定的起点出发,经过所有的边恰好一次,使得路径字典序最小。这是一个典型的欧拉路径问题。 + +由于本题保证了至少存在一种合理的行程,因此,我们直接利用 Hierholzer 算法,输出从起点出发的欧拉路径即可。 + +时间复杂度 $O(m \times \log m)$,空间复杂度 $O(m)$。其中 $m$ 是边的数量。 @@ -73,56 +79,43 @@ tags: ```python class Solution: def findItinerary(self, tickets: List[List[str]]) -> List[str]: - graph = defaultdict(list) - - for src, dst in sorted(tickets, reverse=True): - graph[src].append(dst) - - itinerary = [] - - def dfs(airport): - while graph[airport]: - dfs(graph[airport].pop()) - itinerary.append(airport) - + def dfs(f: str): + while g[f]: + dfs(g[f].pop()) + ans.append(f) + + g = defaultdict(list) + for f, t in sorted(tickets, reverse=True): + g[f].append(t) + ans = [] dfs("JFK") - - return itinerary[::-1] + return ans[::-1] ``` #### Java ```java class Solution { - void dfs(Map> adjLists, List ans, String curr) { - Queue neighbors = adjLists.get(curr); - if (neighbors == null) { - ans.add(curr); - return; - } - while (!neighbors.isEmpty()) { - String neighbor = neighbors.poll(); - dfs(adjLists, ans, neighbor); - } - ans.add(curr); - return; - } + private Map> g = new HashMap<>(); + private List ans = new ArrayList<>(); public List findItinerary(List> tickets) { - Map> adjLists = new HashMap<>(); + Collections.sort(tickets, (a, b) -> b.get(1).compareTo(a.get(1))); for (List ticket : tickets) { - String from = ticket.get(0); - String to = ticket.get(1); - if (!adjLists.containsKey(from)) { - adjLists.put(from, new PriorityQueue<>()); - } - adjLists.get(from).add(to); + g.computeIfAbsent(ticket.get(0), k -> new ArrayList<>()).add(ticket.get(1)); } - List ans = new ArrayList<>(); - dfs(adjLists, ans, "JFK"); + dfs("JFK"); Collections.reverse(ans); return ans; } + + private void dfs(String f) { + while (g.containsKey(f) && !g.get(f).isEmpty()) { + String t = g.get(f).remove(g.get(f).size() - 1); + dfs(t); + } + ans.add(f); + } } ``` @@ -132,36 +125,77 @@ class Solution { class Solution { public: vector findItinerary(vector>& tickets) { - unordered_map, greater>> g; - vector ret; - - // Initialize the graph - for (const auto& t : tickets) { - g[t[0]].push(t[1]); + sort(tickets.rbegin(), tickets.rend()); + unordered_map> g; + for (const auto& ticket : tickets) { + g[ticket[0]].push_back(ticket[1]); } + vector ans; + auto dfs = [&](auto&& dfs, string& f) -> void { + while (!g[f].empty()) { + string t = g[f].back(); + g[f].pop_back(); + dfs(dfs, t); + } + ans.emplace_back(f); + }; + string f = "JFK"; + dfs(dfs, f); + reverse(ans.begin(), ans.end()); + return ans; + } +}; +``` - findItineraryInner(g, ret, "JFK"); +#### Go + +```go +func findItinerary(tickets [][]string) (ans []string) { + sort.Slice(tickets, func(i, j int) bool { + return tickets[i][0] > tickets[j][0] || (tickets[i][0] == tickets[j][0] && tickets[i][1] > tickets[j][1]) + }) + g := make(map[string][]string) + for _, ticket := range tickets { + g[ticket[0]] = append(g[ticket[0]], ticket[1]) + } + var dfs func(f string) + dfs = func(f string) { + for len(g[f]) > 0 { + t := g[f][len(g[f])-1] + g[f] = g[f][:len(g[f])-1] + dfs(t) + } + ans = append(ans, f) + } + dfs("JFK") + for i := 0; i < len(ans)/2; i++ { + ans[i], ans[len(ans)-1-i] = ans[len(ans)-1-i], ans[i] + } + return +} +``` - ret = {ret.rbegin(), ret.rend()}; +#### TypeScript - return ret; +```ts +function findItinerary(tickets: string[][]): string[] { + const g: Record = {}; + tickets.sort((a, b) => b[1].localeCompare(a[1])); + for (const [f, t] of tickets) { + g[f] = g[f] || []; + g[f].push(t); } - - void findItineraryInner(unordered_map, greater>>& g, vector& ret, string cur) { - if (g.count(cur) == 0) { - // This is the end point - ret.push_back(cur); - return; - } else { - while (!g[cur].empty()) { - auto front = g[cur].top(); - g[cur].pop(); - findItineraryInner(g, ret, front); - } - ret.push_back(cur); + const ans: string[] = []; + const dfs = (f: string) => { + while (g[f] && g[f].length) { + const t = g[f].pop()!; + dfs(t); } - } -}; + ans.push(f); + }; + dfs('JFK'); + return ans.reverse(); +} ``` diff --git a/solution/0300-0399/0332.Reconstruct Itinerary/README_EN.md b/solution/0300-0399/0332.Reconstruct Itinerary/README_EN.md index bb688d0f1adab..3fcd849fbd06a 100644 --- a/solution/0300-0399/0332.Reconstruct Itinerary/README_EN.md +++ b/solution/0300-0399/0332.Reconstruct Itinerary/README_EN.md @@ -62,7 +62,13 @@ tags: -### Solution 1 +### Solution 1: Eulerian Path + +The problem is essentially about finding a path that starts from a specified starting point, passes through all the edges exactly once, and has the smallest lexicographical order among all such paths, given $n$ vertices and $m$ edges. This is a classic Eulerian path problem. + +Since the problem guarantees that there is at least one feasible itinerary, we can directly use the Hierholzer algorithm to output the Eulerian path starting from the starting point. + +The time complexity is $O(m \times \log m)$, and the space complexity is $O(m)$. Here, $m$ is the number of edges. @@ -71,56 +77,43 @@ tags: ```python class Solution: def findItinerary(self, tickets: List[List[str]]) -> List[str]: - graph = defaultdict(list) - - for src, dst in sorted(tickets, reverse=True): - graph[src].append(dst) - - itinerary = [] - - def dfs(airport): - while graph[airport]: - dfs(graph[airport].pop()) - itinerary.append(airport) - + def dfs(f: str): + while g[f]: + dfs(g[f].pop()) + ans.append(f) + + g = defaultdict(list) + for f, t in sorted(tickets, reverse=True): + g[f].append(t) + ans = [] dfs("JFK") - - return itinerary[::-1] + return ans[::-1] ``` #### Java ```java class Solution { - void dfs(Map> adjLists, List ans, String curr) { - Queue neighbors = adjLists.get(curr); - if (neighbors == null) { - ans.add(curr); - return; - } - while (!neighbors.isEmpty()) { - String neighbor = neighbors.poll(); - dfs(adjLists, ans, neighbor); - } - ans.add(curr); - return; - } + private Map> g = new HashMap<>(); + private List ans = new ArrayList<>(); public List findItinerary(List> tickets) { - Map> adjLists = new HashMap<>(); + Collections.sort(tickets, (a, b) -> b.get(1).compareTo(a.get(1))); for (List ticket : tickets) { - String from = ticket.get(0); - String to = ticket.get(1); - if (!adjLists.containsKey(from)) { - adjLists.put(from, new PriorityQueue<>()); - } - adjLists.get(from).add(to); + g.computeIfAbsent(ticket.get(0), k -> new ArrayList<>()).add(ticket.get(1)); } - List ans = new ArrayList<>(); - dfs(adjLists, ans, "JFK"); + dfs("JFK"); Collections.reverse(ans); return ans; } + + private void dfs(String f) { + while (g.containsKey(f) && !g.get(f).isEmpty()) { + String t = g.get(f).remove(g.get(f).size() - 1); + dfs(t); + } + ans.add(f); + } } ``` @@ -130,36 +123,77 @@ class Solution { class Solution { public: vector findItinerary(vector>& tickets) { - unordered_map, greater>> g; - vector ret; - - // Initialize the graph - for (const auto& t : tickets) { - g[t[0]].push(t[1]); + sort(tickets.rbegin(), tickets.rend()); + unordered_map> g; + for (const auto& ticket : tickets) { + g[ticket[0]].push_back(ticket[1]); } + vector ans; + auto dfs = [&](auto&& dfs, string& f) -> void { + while (!g[f].empty()) { + string t = g[f].back(); + g[f].pop_back(); + dfs(dfs, t); + } + ans.emplace_back(f); + }; + string f = "JFK"; + dfs(dfs, f); + reverse(ans.begin(), ans.end()); + return ans; + } +}; +``` - findItineraryInner(g, ret, "JFK"); +#### Go + +```go +func findItinerary(tickets [][]string) (ans []string) { + sort.Slice(tickets, func(i, j int) bool { + return tickets[i][0] > tickets[j][0] || (tickets[i][0] == tickets[j][0] && tickets[i][1] > tickets[j][1]) + }) + g := make(map[string][]string) + for _, ticket := range tickets { + g[ticket[0]] = append(g[ticket[0]], ticket[1]) + } + var dfs func(f string) + dfs = func(f string) { + for len(g[f]) > 0 { + t := g[f][len(g[f])-1] + g[f] = g[f][:len(g[f])-1] + dfs(t) + } + ans = append(ans, f) + } + dfs("JFK") + for i := 0; i < len(ans)/2; i++ { + ans[i], ans[len(ans)-1-i] = ans[len(ans)-1-i], ans[i] + } + return +} +``` - ret = {ret.rbegin(), ret.rend()}; +#### TypeScript - return ret; +```ts +function findItinerary(tickets: string[][]): string[] { + const g: Record = {}; + tickets.sort((a, b) => b[1].localeCompare(a[1])); + for (const [f, t] of tickets) { + g[f] = g[f] || []; + g[f].push(t); } - - void findItineraryInner(unordered_map, greater>>& g, vector& ret, string cur) { - if (g.count(cur) == 0) { - // This is the end point - ret.push_back(cur); - return; - } else { - while (!g[cur].empty()) { - auto front = g[cur].top(); - g[cur].pop(); - findItineraryInner(g, ret, front); - } - ret.push_back(cur); + const ans: string[] = []; + const dfs = (f: string) => { + while (g[f] && g[f].length) { + const t = g[f].pop()!; + dfs(t); } - } -}; + ans.push(f); + }; + dfs('JFK'); + return ans.reverse(); +} ``` diff --git a/solution/0300-0399/0332.Reconstruct Itinerary/Solution.cpp b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.cpp index c9a7344be9fee..daa0b3bd96ab8 100644 --- a/solution/0300-0399/0332.Reconstruct Itinerary/Solution.cpp +++ b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.cpp @@ -1,33 +1,23 @@ class Solution { public: vector findItinerary(vector>& tickets) { - unordered_map, greater>> g; - vector ret; - - // Initialize the graph - for (const auto& t : tickets) { - g[t[0]].push(t[1]); + sort(tickets.rbegin(), tickets.rend()); + unordered_map> g; + for (const auto& ticket : tickets) { + g[ticket[0]].push_back(ticket[1]); } - - findItineraryInner(g, ret, "JFK"); - - ret = {ret.rbegin(), ret.rend()}; - - return ret; - } - - void findItineraryInner(unordered_map, greater>>& g, vector& ret, string cur) { - if (g.count(cur) == 0) { - // This is the end point - ret.push_back(cur); - return; - } else { - while (!g[cur].empty()) { - auto front = g[cur].top(); - g[cur].pop(); - findItineraryInner(g, ret, front); + vector ans; + auto dfs = [&](auto&& dfs, string& f) -> void { + while (!g[f].empty()) { + string t = g[f].back(); + g[f].pop_back(); + dfs(dfs, t); } - ret.push_back(cur); - } + ans.emplace_back(f); + }; + string f = "JFK"; + dfs(dfs, f); + reverse(ans.begin(), ans.end()); + return ans; } }; \ No newline at end of file diff --git a/solution/0300-0399/0332.Reconstruct Itinerary/Solution.go b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.go new file mode 100644 index 0000000000000..35ba5bc6ee499 --- /dev/null +++ b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.go @@ -0,0 +1,23 @@ +func findItinerary(tickets [][]string) (ans []string) { + sort.Slice(tickets, func(i, j int) bool { + return tickets[i][0] > tickets[j][0] || (tickets[i][0] == tickets[j][0] && tickets[i][1] > tickets[j][1]) + }) + g := make(map[string][]string) + for _, ticket := range tickets { + g[ticket[0]] = append(g[ticket[0]], ticket[1]) + } + var dfs func(f string) + dfs = func(f string) { + for len(g[f]) > 0 { + t := g[f][len(g[f])-1] + g[f] = g[f][:len(g[f])-1] + dfs(t) + } + ans = append(ans, f) + } + dfs("JFK") + for i := 0; i < len(ans)/2; i++ { + ans[i], ans[len(ans)-1-i] = ans[len(ans)-1-i], ans[i] + } + return +} \ No newline at end of file diff --git a/solution/0300-0399/0332.Reconstruct Itinerary/Solution.java b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.java index 970cd30092f14..ddc8efbf45515 100644 --- a/solution/0300-0399/0332.Reconstruct Itinerary/Solution.java +++ b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.java @@ -1,31 +1,22 @@ class Solution { - void dfs(Map> adjLists, List ans, String curr) { - Queue neighbors = adjLists.get(curr); - if (neighbors == null) { - ans.add(curr); - return; - } - while (!neighbors.isEmpty()) { - String neighbor = neighbors.poll(); - dfs(adjLists, ans, neighbor); - } - ans.add(curr); - return; - } + private Map> g = new HashMap<>(); + private List ans = new ArrayList<>(); public List findItinerary(List> tickets) { - Map> adjLists = new HashMap<>(); + Collections.sort(tickets, (a, b) -> b.get(1).compareTo(a.get(1))); for (List ticket : tickets) { - String from = ticket.get(0); - String to = ticket.get(1); - if (!adjLists.containsKey(from)) { - adjLists.put(from, new PriorityQueue<>()); - } - adjLists.get(from).add(to); + g.computeIfAbsent(ticket.get(0), k -> new ArrayList<>()).add(ticket.get(1)); } - List ans = new ArrayList<>(); - dfs(adjLists, ans, "JFK"); + dfs("JFK"); Collections.reverse(ans); return ans; } + + private void dfs(String f) { + while (g.containsKey(f) && !g.get(f).isEmpty()) { + String t = g.get(f).remove(g.get(f).size() - 1); + dfs(t); + } + ans.add(f); + } } \ No newline at end of file diff --git a/solution/0300-0399/0332.Reconstruct Itinerary/Solution.py b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.py index 8b6c452a44ca2..7614c393c9f7f 100644 --- a/solution/0300-0399/0332.Reconstruct Itinerary/Solution.py +++ b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.py @@ -1,17 +1,13 @@ class Solution: def findItinerary(self, tickets: List[List[str]]) -> List[str]: - graph = defaultdict(list) - - for src, dst in sorted(tickets, reverse=True): - graph[src].append(dst) - - itinerary = [] - - def dfs(airport): - while graph[airport]: - dfs(graph[airport].pop()) - itinerary.append(airport) - + def dfs(f: str): + while g[f]: + dfs(g[f].pop()) + ans.append(f) + + g = defaultdict(list) + for f, t in sorted(tickets, reverse=True): + g[f].append(t) + ans = [] dfs("JFK") - - return itinerary[::-1] + return ans[::-1] diff --git a/solution/0300-0399/0332.Reconstruct Itinerary/Solution.ts b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.ts new file mode 100644 index 0000000000000..d8a61a461a1f5 --- /dev/null +++ b/solution/0300-0399/0332.Reconstruct Itinerary/Solution.ts @@ -0,0 +1,18 @@ +function findItinerary(tickets: string[][]): string[] { + const g: Record = {}; + tickets.sort((a, b) => b[1].localeCompare(a[1])); + for (const [f, t] of tickets) { + g[f] = g[f] || []; + g[f].push(t); + } + const ans: string[] = []; + const dfs = (f: string) => { + while (g[f] && g[f].length) { + const t = g[f].pop()!; + dfs(t); + } + ans.push(f); + }; + dfs('JFK'); + return ans.reverse(); +}