From 19ab65e85849f9beff2179e5806ca5b47c262138 Mon Sep 17 00:00:00 2001 From: ShusenTang Date: Fri, 6 Dec 2019 22:26:29 +0800 Subject: [PATCH] add 332 --- solutions/332. Reconstruct Itinerary.md | 137 ++++++++++++++++++++++++ 1 file changed, 137 insertions(+) create mode 100644 solutions/332. Reconstruct Itinerary.md diff --git a/solutions/332. Reconstruct Itinerary.md b/solutions/332. Reconstruct Itinerary.md new file mode 100644 index 0000000..64ce0e1 --- /dev/null +++ b/solutions/332. Reconstruct Itinerary.md @@ -0,0 +1,137 @@ +# [332. Reconstruct Itinerary](https://leetcode.com/problems/reconstruct-itinerary/) + +# 思路 +这道题给我们一堆飞机票,让我们安排行程路线,必须用完所有机票,如果有多种方法,取其中字母顺序小的那种方法。 + + +## 思路一、Brute Force + +这道题目可以转化成一个图来描述。图中每一个点就是一个地点,每张票代表的就是一个有向的边(需要注意的是图中可以存在环)。题目转换成要求一条搜索路径,要求走完所有边且每条边只能走一次。 + +所以最直接的想法就是直接普通的DFS,尝试所有可能的路径,具体步骤如下: +1. 把输入转换成为图的形式,要求给定一个地点,就能快速地知道它所连接的邻居点们,并且可以lexical order的顺序的访问它们,我们可以用数据结构`unordered_map>`来表示这个图。 +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>&G, string from, + unordered_map>&visited, + vector &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 findItinerary(vector>& tickets) { + unordered_map>G; + unordered_map>visited; + setcity; + 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(G[a].size(), 0); + } + + vectorres; + DFS(G, "JFK", visited, res); + return res; + } +}; +``` + +## 思路二 +``` C++ +class Solution { +private: + unordered_map>G; + vectorres; + // 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 findItinerary(vector>& tickets) { + for(auto &t: tickets) + G[t[0]].insert(t[1]); + + DFS("JFK"); + reverse(res.begin(), res.end()); + return res; + } +}; +``` \ No newline at end of file