1. 程式人生 > >[LeetCode]332 航程重建

[LeetCode]332 航程重建

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;
    }
};