Skip to content

Commit fecf7d9

Browse files
authored
feat: add solutions to lc problem: No.0332 (#3278)
No.0332.Reconstruct Itinerary
1 parent 9bc1ff1 commit fecf7d9

File tree

7 files changed

+270
-184
lines changed

7 files changed

+270
-184
lines changed

solution/0300-0399/0332.Reconstruct Itinerary/README.md

Lines changed: 95 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,13 @@ tags:
6464

6565
<!-- solution:start -->
6666

67-
### 方法一
67+
### 方法一:欧拉路径
68+
69+
题目实际上是给定 $n$ 个点和 $m$ 条边,要求从指定的起点出发,经过所有的边恰好一次,使得路径字典序最小。这是一个典型的欧拉路径问题。
70+
71+
由于本题保证了至少存在一种合理的行程,因此,我们直接利用 Hierholzer 算法,输出从起点出发的欧拉路径即可。
72+
73+
时间复杂度 $O(m \times \log m)$,空间复杂度 $O(m)$。其中 $m$ 是边的数量。
6874

6975
<!-- tabs:start -->
7076

@@ -73,56 +79,43 @@ tags:
7379
```python
7480
class Solution:
7581
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
76-
graph = defaultdict(list)
77-
78-
for src, dst in sorted(tickets, reverse=True):
79-
graph[src].append(dst)
80-
81-
itinerary = []
82-
83-
def dfs(airport):
84-
while graph[airport]:
85-
dfs(graph[airport].pop())
86-
itinerary.append(airport)
87-
82+
def dfs(f: str):
83+
while g[f]:
84+
dfs(g[f].pop())
85+
ans.append(f)
86+
87+
g = defaultdict(list)
88+
for f, t in sorted(tickets, reverse=True):
89+
g[f].append(t)
90+
ans = []
8891
dfs("JFK")
89-
90-
return itinerary[::-1]
92+
return ans[::-1]
9193
```
9294

9395
#### Java
9496

9597
```java
9698
class Solution {
97-
void dfs(Map<String, Queue<String>> adjLists, List<String> ans, String curr) {
98-
Queue<String> neighbors = adjLists.get(curr);
99-
if (neighbors == null) {
100-
ans.add(curr);
101-
return;
102-
}
103-
while (!neighbors.isEmpty()) {
104-
String neighbor = neighbors.poll();
105-
dfs(adjLists, ans, neighbor);
106-
}
107-
ans.add(curr);
108-
return;
109-
}
99+
private Map<String, List<String>> g = new HashMap<>();
100+
private List<String> ans = new ArrayList<>();
110101

111102
public List<String> findItinerary(List<List<String>> tickets) {
112-
Map<String, Queue<String>> adjLists = new HashMap<>();
103+
Collections.sort(tickets, (a, b) -> b.get(1).compareTo(a.get(1)));
113104
for (List<String> ticket : tickets) {
114-
String from = ticket.get(0);
115-
String to = ticket.get(1);
116-
if (!adjLists.containsKey(from)) {
117-
adjLists.put(from, new PriorityQueue<>());
118-
}
119-
adjLists.get(from).add(to);
105+
g.computeIfAbsent(ticket.get(0), k -> new ArrayList<>()).add(ticket.get(1));
120106
}
121-
List<String> ans = new ArrayList<>();
122-
dfs(adjLists, ans, "JFK");
107+
dfs("JFK");
123108
Collections.reverse(ans);
124109
return ans;
125110
}
111+
112+
private void dfs(String f) {
113+
while (g.containsKey(f) && !g.get(f).isEmpty()) {
114+
String t = g.get(f).remove(g.get(f).size() - 1);
115+
dfs(t);
116+
}
117+
ans.add(f);
118+
}
126119
}
127120
```
128121

@@ -132,36 +125,77 @@ class Solution {
132125
class Solution {
133126
public:
134127
vector<string> findItinerary(vector<vector<string>>& tickets) {
135-
unordered_map<string, priority_queue<string, vector<string>, greater<string>>> g;
136-
vector<string> ret;
137-
138-
// Initialize the graph
139-
for (const auto& t : tickets) {
140-
g[t[0]].push(t[1]);
128+
sort(tickets.rbegin(), tickets.rend());
129+
unordered_map<string, vector<string>> g;
130+
for (const auto& ticket : tickets) {
131+
g[ticket[0]].push_back(ticket[1]);
141132
}
133+
vector<string> ans;
134+
auto dfs = [&](auto&& dfs, string& f) -> void {
135+
while (!g[f].empty()) {
136+
string t = g[f].back();
137+
g[f].pop_back();
138+
dfs(dfs, t);
139+
}
140+
ans.emplace_back(f);
141+
};
142+
string f = "JFK";
143+
dfs(dfs, f);
144+
reverse(ans.begin(), ans.end());
145+
return ans;
146+
}
147+
};
148+
```
142149
143-
findItineraryInner(g, ret, "JFK");
150+
#### Go
151+
152+
```go
153+
func findItinerary(tickets [][]string) (ans []string) {
154+
sort.Slice(tickets, func(i, j int) bool {
155+
return tickets[i][0] > tickets[j][0] || (tickets[i][0] == tickets[j][0] && tickets[i][1] > tickets[j][1])
156+
})
157+
g := make(map[string][]string)
158+
for _, ticket := range tickets {
159+
g[ticket[0]] = append(g[ticket[0]], ticket[1])
160+
}
161+
var dfs func(f string)
162+
dfs = func(f string) {
163+
for len(g[f]) > 0 {
164+
t := g[f][len(g[f])-1]
165+
g[f] = g[f][:len(g[f])-1]
166+
dfs(t)
167+
}
168+
ans = append(ans, f)
169+
}
170+
dfs("JFK")
171+
for i := 0; i < len(ans)/2; i++ {
172+
ans[i], ans[len(ans)-1-i] = ans[len(ans)-1-i], ans[i]
173+
}
174+
return
175+
}
176+
```
144177

145-
ret = {ret.rbegin(), ret.rend()};
178+
#### TypeScript
146179

147-
return ret;
180+
```ts
181+
function findItinerary(tickets: string[][]): string[] {
182+
const g: Record<string, string[]> = {};
183+
tickets.sort((a, b) => b[1].localeCompare(a[1]));
184+
for (const [f, t] of tickets) {
185+
g[f] = g[f] || [];
186+
g[f].push(t);
148187
}
149-
150-
void findItineraryInner(unordered_map<string, priority_queue<string, vector<string>, greater<string>>>& g, vector<string>& ret, string cur) {
151-
if (g.count(cur) == 0) {
152-
// This is the end point
153-
ret.push_back(cur);
154-
return;
155-
} else {
156-
while (!g[cur].empty()) {
157-
auto front = g[cur].top();
158-
g[cur].pop();
159-
findItineraryInner(g, ret, front);
160-
}
161-
ret.push_back(cur);
188+
const ans: string[] = [];
189+
const dfs = (f: string) => {
190+
while (g[f] && g[f].length) {
191+
const t = g[f].pop()!;
192+
dfs(t);
162193
}
163-
}
164-
};
194+
ans.push(f);
195+
};
196+
dfs('JFK');
197+
return ans.reverse();
198+
}
165199
```
166200

167201
<!-- tabs:end -->

solution/0300-0399/0332.Reconstruct Itinerary/README_EN.md

Lines changed: 95 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,13 @@ tags:
6262

6363
<!-- solution:start -->
6464

65-
### Solution 1
65+
### Solution 1: Eulerian Path
66+
67+
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.
68+
69+
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.
70+
71+
The time complexity is $O(m \times \log m)$, and the space complexity is $O(m)$. Here, $m$ is the number of edges.
6672

6773
<!-- tabs:start -->
6874

@@ -71,56 +77,43 @@ tags:
7177
```python
7278
class Solution:
7379
def findItinerary(self, tickets: List[List[str]]) -> List[str]:
74-
graph = defaultdict(list)
75-
76-
for src, dst in sorted(tickets, reverse=True):
77-
graph[src].append(dst)
78-
79-
itinerary = []
80-
81-
def dfs(airport):
82-
while graph[airport]:
83-
dfs(graph[airport].pop())
84-
itinerary.append(airport)
85-
80+
def dfs(f: str):
81+
while g[f]:
82+
dfs(g[f].pop())
83+
ans.append(f)
84+
85+
g = defaultdict(list)
86+
for f, t in sorted(tickets, reverse=True):
87+
g[f].append(t)
88+
ans = []
8689
dfs("JFK")
87-
88-
return itinerary[::-1]
90+
return ans[::-1]
8991
```
9092

9193
#### Java
9294

9395
```java
9496
class Solution {
95-
void dfs(Map<String, Queue<String>> adjLists, List<String> ans, String curr) {
96-
Queue<String> neighbors = adjLists.get(curr);
97-
if (neighbors == null) {
98-
ans.add(curr);
99-
return;
100-
}
101-
while (!neighbors.isEmpty()) {
102-
String neighbor = neighbors.poll();
103-
dfs(adjLists, ans, neighbor);
104-
}
105-
ans.add(curr);
106-
return;
107-
}
97+
private Map<String, List<String>> g = new HashMap<>();
98+
private List<String> ans = new ArrayList<>();
10899

109100
public List<String> findItinerary(List<List<String>> tickets) {
110-
Map<String, Queue<String>> adjLists = new HashMap<>();
101+
Collections.sort(tickets, (a, b) -> b.get(1).compareTo(a.get(1)));
111102
for (List<String> ticket : tickets) {
112-
String from = ticket.get(0);
113-
String to = ticket.get(1);
114-
if (!adjLists.containsKey(from)) {
115-
adjLists.put(from, new PriorityQueue<>());
116-
}
117-
adjLists.get(from).add(to);
103+
g.computeIfAbsent(ticket.get(0), k -> new ArrayList<>()).add(ticket.get(1));
118104
}
119-
List<String> ans = new ArrayList<>();
120-
dfs(adjLists, ans, "JFK");
105+
dfs("JFK");
121106
Collections.reverse(ans);
122107
return ans;
123108
}
109+
110+
private void dfs(String f) {
111+
while (g.containsKey(f) && !g.get(f).isEmpty()) {
112+
String t = g.get(f).remove(g.get(f).size() - 1);
113+
dfs(t);
114+
}
115+
ans.add(f);
116+
}
124117
}
125118
```
126119

@@ -130,36 +123,77 @@ class Solution {
130123
class Solution {
131124
public:
132125
vector<string> findItinerary(vector<vector<string>>& tickets) {
133-
unordered_map<string, priority_queue<string, vector<string>, greater<string>>> g;
134-
vector<string> ret;
135-
136-
// Initialize the graph
137-
for (const auto& t : tickets) {
138-
g[t[0]].push(t[1]);
126+
sort(tickets.rbegin(), tickets.rend());
127+
unordered_map<string, vector<string>> g;
128+
for (const auto& ticket : tickets) {
129+
g[ticket[0]].push_back(ticket[1]);
139130
}
131+
vector<string> ans;
132+
auto dfs = [&](auto&& dfs, string& f) -> void {
133+
while (!g[f].empty()) {
134+
string t = g[f].back();
135+
g[f].pop_back();
136+
dfs(dfs, t);
137+
}
138+
ans.emplace_back(f);
139+
};
140+
string f = "JFK";
141+
dfs(dfs, f);
142+
reverse(ans.begin(), ans.end());
143+
return ans;
144+
}
145+
};
146+
```
140147
141-
findItineraryInner(g, ret, "JFK");
148+
#### Go
149+
150+
```go
151+
func findItinerary(tickets [][]string) (ans []string) {
152+
sort.Slice(tickets, func(i, j int) bool {
153+
return tickets[i][0] > tickets[j][0] || (tickets[i][0] == tickets[j][0] && tickets[i][1] > tickets[j][1])
154+
})
155+
g := make(map[string][]string)
156+
for _, ticket := range tickets {
157+
g[ticket[0]] = append(g[ticket[0]], ticket[1])
158+
}
159+
var dfs func(f string)
160+
dfs = func(f string) {
161+
for len(g[f]) > 0 {
162+
t := g[f][len(g[f])-1]
163+
g[f] = g[f][:len(g[f])-1]
164+
dfs(t)
165+
}
166+
ans = append(ans, f)
167+
}
168+
dfs("JFK")
169+
for i := 0; i < len(ans)/2; i++ {
170+
ans[i], ans[len(ans)-1-i] = ans[len(ans)-1-i], ans[i]
171+
}
172+
return
173+
}
174+
```
142175

143-
ret = {ret.rbegin(), ret.rend()};
176+
#### TypeScript
144177

145-
return ret;
178+
```ts
179+
function findItinerary(tickets: string[][]): string[] {
180+
const g: Record<string, string[]> = {};
181+
tickets.sort((a, b) => b[1].localeCompare(a[1]));
182+
for (const [f, t] of tickets) {
183+
g[f] = g[f] || [];
184+
g[f].push(t);
146185
}
147-
148-
void findItineraryInner(unordered_map<string, priority_queue<string, vector<string>, greater<string>>>& g, vector<string>& ret, string cur) {
149-
if (g.count(cur) == 0) {
150-
// This is the end point
151-
ret.push_back(cur);
152-
return;
153-
} else {
154-
while (!g[cur].empty()) {
155-
auto front = g[cur].top();
156-
g[cur].pop();
157-
findItineraryInner(g, ret, front);
158-
}
159-
ret.push_back(cur);
186+
const ans: string[] = [];
187+
const dfs = (f: string) => {
188+
while (g[f] && g[f].length) {
189+
const t = g[f].pop()!;
190+
dfs(t);
160191
}
161-
}
162-
};
192+
ans.push(f);
193+
};
194+
dfs('JFK');
195+
return ans.reverse();
196+
}
163197
```
164198

165199
<!-- tabs:end -->

0 commit comments

Comments
 (0)