mirror of
https://github.com/ShusenTang/LeetCode.git
synced 2024-09-02 14:20:01 +00:00
add 332
This commit is contained in:
parent
5615c1ca7e
commit
19ab65e858
137
solutions/332. Reconstruct Itinerary.md
Normal file
137
solutions/332. Reconstruct Itinerary.md
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
# [332. Reconstruct Itinerary](https://leetcode.com/problems/reconstruct-itinerary/)
|
||||||
|
|
||||||
|
# 思路
|
||||||
|
这道题给我们一堆飞机票,让我们安排行程路线,必须用完所有机票,如果有多种方法,取其中字母顺序小的那种方法。
|
||||||
|
|
||||||
|
|
||||||
|
## 思路一、Brute Force
|
||||||
|
|
||||||
|
这道题目可以转化成一个图来描述。图中每一个点就是一个地点,每张票代表的就是一个有向的边(需要注意的是图中可以存在环)。题目转换成要求一条搜索路径,要求走完所有边且每条边只能走一次。
|
||||||
|
|
||||||
|
所以最直接的想法就是直接普通的DFS,尝试所有可能的路径,具体步骤如下:
|
||||||
|
1. 把输入转换成为图的形式,要求给定一个地点,就能快速地知道它所连接的邻居点们,并且可以lexical order的顺序的访问它们,我们可以用数据结构`unordered_map<string, vector<string>>`来表示这个图。
|
||||||
|
2. 在构造的图上从JFK开始做DFS,访问所有能走的路,同时记录已访问过的边,一旦边数达到票数加1,说明已经用完所有票,直接return,否则应该回溯。
|
||||||
|
|
||||||
|
|
||||||
|
## 思路二、欧拉路径(Hierholzer算法)
|
||||||
|
|
||||||
|
题目要求的这个路径其实叫做欧拉路径,欧拉路径是指一条包含图中所有边的一条路径,该路径中所有的边会且仅会出现一次。
|
||||||
|
|
||||||
|
```
|
||||||
|
一个无向图中存在欧拉路径,当且仅当下面两条性质同时满足:
|
||||||
|
* 图是连通的
|
||||||
|
* 图中每个顶点的度均为偶数
|
||||||
|
|
||||||
|
而一个有向图存在欧拉路径,当且仅当下面两条性质同时满足:
|
||||||
|
* 图是连通的
|
||||||
|
* 图中每个顶点入度和出度相同
|
||||||
|
```
|
||||||
|
|
||||||
|
那么,这个题目就可以转化成:已知有向图中存在欧拉路径,如何找到一个欧拉路径?
|
||||||
|
|
||||||
|
Hierholzer算法是求欧拉路径的一个经典算法,它其实也是DFS,其伪代码如下:
|
||||||
|
```
|
||||||
|
// path逆序记录着欧拉路径
|
||||||
|
DFS(u){
|
||||||
|
While u存在未被访问的边e(u,v):
|
||||||
|
记录边e(u,v)为访问
|
||||||
|
DFS(v)
|
||||||
|
path.push(u)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
由于上述过程不用回溯,所以我们不用visited数组来记录某条边已被访问过而是直接将改边删除即可,即
|
||||||
|
```
|
||||||
|
// path逆序记录着欧拉路径
|
||||||
|
DFS(u){
|
||||||
|
While u存在边e(u,v):
|
||||||
|
删除边e(u,v)
|
||||||
|
DFS(v)
|
||||||
|
path.push(u)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
上述过程的图示举例可参考[此博文](https://www.geeksforgeeks.org/hierholzers-algorithm-directed-graph/)。由于每条边访问后就被删掉了,所以时间复杂度为O(E),E为边数。
|
||||||
|
|
||||||
|
|
||||||
|
这道题目运用经典的hierholzer算法需要注意的是,由于我们需要优先访问 lexical order 比较小的点,所以我们用multiset存放每个节点的所有邻居,这样可以维持有序。
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# C++
|
||||||
|
## 思路一
|
||||||
|
``` C++
|
||||||
|
class Solution {
|
||||||
|
private:
|
||||||
|
int tickets_num;
|
||||||
|
void DFS(unordered_map<string, vector<string>>&G, string from,
|
||||||
|
unordered_map<string, vector<int>>&visited,
|
||||||
|
vector<string> &res){
|
||||||
|
res.push_back(from);
|
||||||
|
if(res.size() == tickets_num + 1) return;
|
||||||
|
|
||||||
|
int size = G[from].size();
|
||||||
|
for(int i = 0; i < size; i++){
|
||||||
|
string next = G[from][i];
|
||||||
|
if(visited[from][i]) continue;
|
||||||
|
|
||||||
|
visited[from][i] = 1;
|
||||||
|
DFS(G, next, visited, res);
|
||||||
|
if(res.size() == tickets_num + 1) return;
|
||||||
|
// 回溯
|
||||||
|
visited[from][i] = 0;
|
||||||
|
res.pop_back();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
vector<string> findItinerary(vector<vector<string>>& tickets) {
|
||||||
|
unordered_map<string, vector<string>>G;
|
||||||
|
unordered_map<string, vector<int>>visited;
|
||||||
|
set<string>city;
|
||||||
|
tickets_num = tickets.size();
|
||||||
|
for(int i = 0; i < tickets.size(); i++){
|
||||||
|
G[tickets[i][0]].push_back(tickets[i][1]);
|
||||||
|
city.insert(tickets[i][0]);
|
||||||
|
city.insert(tickets[i][1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
for(auto &a: city){
|
||||||
|
sort(G[a].begin(), G[a].end()); // 按照字符顺序排序
|
||||||
|
visited[a] = vector<int>(G[a].size(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
vector<string>res;
|
||||||
|
DFS(G, "JFK", visited, res);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
||||||
|
|
||||||
|
## 思路二
|
||||||
|
``` C++
|
||||||
|
class Solution {
|
||||||
|
private:
|
||||||
|
unordered_map<string, multiset<string>>G;
|
||||||
|
vector<string>res;
|
||||||
|
// Hierholzer算法
|
||||||
|
void DFS(string from){
|
||||||
|
while(!G[from].empty()){
|
||||||
|
auto next_ptr = G[from].begin();
|
||||||
|
string next = *next_ptr;
|
||||||
|
G[from].erase(next_ptr);
|
||||||
|
DFS(next);
|
||||||
|
}
|
||||||
|
res.push_back(from);
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
vector<string> findItinerary(vector<vector<string>>& tickets) {
|
||||||
|
for(auto &t: tickets)
|
||||||
|
G[t[0]].insert(t[1]);
|
||||||
|
|
||||||
|
DFS("JFK");
|
||||||
|
reverse(res.begin(), res.end());
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
```
|
Loading…
Reference in New Issue
Block a user