Reconstruct Itinerary(航程重建)
【难度:Medium】
Given a list of airline tickets represented by pairs of departure and arrival airports [from, to], reconstruct the itinerary in order. All of the tickets belong to a man who departs from JFK. Thus, the itinerary must begin with JFK.
Note:
If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string. For example, the itinerary [“JFK”, “LGA”] has a smaller lexical order than [“JFK”, “LGB”].
All airports are represented by three capital letters (IATA code).
You may assume all tickets form at least one valid itinerary.
Example 1:
tickets = [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
Return [“JFK”, “MUC”, “LHR”, “SFO”, “SJC”].
Example 2:
tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
Return [“JFK”,”ATL”,”JFK”,”SFO”,”ATL”,”SFO”].
Another possible reconstruction is
[“JFK”,”SFO”,”ATL”,”JFK”,”ATL”,”SFO”].
But it is larger in lexical order.
给定一系列飞机票,飞机票上是起飞点和目的地[from,to]组成的一对字符串,根据这些飞机票按最小的字典顺序重构完整的航程。所有航程由JFK开始,到JFK结束。
可能会有多个解,取最小字典序作为答案。
解题思路
一道DFS和图结合的题。首先我们要考虑的是如何根据飞机票的信息构建出这些航程之间的关联。一种方法是利用哈希,将出发点和终点对应起来。由于出发点可以对应多个终点(根据常识),是一对多的映射关系,这里可以使用multiset来存储,并且set的自动排序帮助我们解决了字典序的问题。那么图的数据结构表示就是map<string,multiset<string>>
。
接着要将所有飞机票的信息存储到map中,从航程起点JFK开始进行深搜。这里利用stack来帮助我们记忆中间的状态,即栈顶为当前的停留机场。那么当栈非空时,取出栈顶元素,在map中搜索在当前机场有无下一个目标:
1)如果当前机场在map中搜索不到映射的结果,说明该点已搜索完毕,将其存储进ans中,出栈;
2)否则将其在map中的搜索到的multiset的第一个结果压栈,并从multiset中remove该结果,进行下一次搜索,直到1)情况出现。
那么当循环结束时,ans就保留了DFS的搜索路径,但他是逆序的,因为会先搜索到终点,最后才是起点。所以需要将ans翻转。
c++代码如下:
class Solution {
public:
vector<string> findItinerary(vector<pair<string, string>> tickets) {
vector<string> ans;
map<string, multiset<string>> graph;
if (tickets.empty())
return ans;
string from = "JFK";
for (pair<string,string> i : tickets) {
graph[i.first].insert(i.second);
}
stack<string> s;
s.push(from);
while (!s.empty()) {
from = s.top();
if (graph[from].empty()) {
ans.push_back(from);
s.pop();
} else {
s.push(*(graph[from].begin()));
graph[from].erase(graph[from].begin());
}
}
reverse(ans.begin(),ans.end());
return ans;
}
};