1. 程式人生 > 其它 >332. 重新安排行程(歐拉回路問題)

332. 重新安排行程(歐拉回路問題)

題目

給定一個機票的字串二維陣列 [from, to],子陣列中的兩個成員分別表示飛機出發和降落的機場地點,對該行程進行重新規劃排序。所有這些機票都屬於一個從 JFK(肯尼迪國際機場)出發的先生,所以該行程必須從 JFK 開始。

提示:
如果存在多種有效的行程,請你按字元自然排序返回最小的行程組合。例如,行程 ["JFK", "LGA"] 與 ["JFK", "LGB"] 相比就更小,排序更靠前
所有的機場都用三個大寫字母表示(機場程式碼)。
假定所有機票至少存在一種合理的行程。
所有的機票必須都用一次 且 只能用一次。

示例 1:
輸入:[["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
輸出:["JFK", "MUC", "LHR", "SFO", "SJC"]

示例 2:
輸入:[["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
輸出:["JFK","ATL","JFK","SFO","ATL","SFO"]
解釋:另一種有效的行程是["JFK","SFO","ATL","JFK","ATL","SFO"]。但是它自然排序更大更靠後。

深度優先搜尋

這道題是要求按字典序的歐拉回路,有以下幾個難點:
(1)如何保證得到的歐拉回路按字典序最小?
一種很直接的思路是得到所有歐拉回路然後找到其中字典序最小的那一個。實際上有更簡便的方法,可以使得只得到一個歐拉回路,這個歐拉回路就是字典序最小的那一個。

方法是將每個頂點指向的頂點放入最小堆中,我們優先訪問字典順序小的節點ATL即可。因此,我們使用貪心策略,優先訪問字典順序小的頂點。

上面例子可以看出,我們別無選擇必須先從 JFK 到 NRT 再回 JFK,最後到達 KUL 作為終點。如果我們按照字典順序先到 KUL,就進入了 “死路”。但是上一個例子我們提到了,優先訪問字典順序小的頂點,那麼我們第一次肯定是先到 KUL,這就走不通了,那怎麼解決呢?當我們採用 DFS 方式遍歷圖時,需要將訪問到的節點逆序插入到結果集。因此第一個訪問到的節點將出現在結果集最後面,而我們是以順序的方式來檢視結果。如果第一個訪問的節點是 “孤島節點”,他會出現在結果集的最後。當我們順序讀取結果集時,這種 “孤島節點” 是最後遇到的,是圖遍歷的終點,這樣就沒有問題了。

(2)如何標記邊為“已訪問”?
標記頂點是否已訪問容易,但如何標記邊已訪問呢? 由於整個演算法過程只得到一條歐拉回路,也就不需要恢復訪問狀態的步驟(注意區分DFS和回溯的區別,回溯有恢復狀態的步驟),換句話說,每條邊僅經過一次,因此可以用刪除邊來替代標記。

    private Map<String, PriorityQueue<String>> map = new HashMap<>();

    private List<String> resList = new LinkedList<>();

    public List<String> findItinerary(List<List<String>> tickets) {
        for (List<String> ticket : tickets) {
            String src = ticket.get(0);
            String dst = ticket.get(1);
            if (!map.containsKey(src)) {
                PriorityQueue<String> pq = new PriorityQueue<>();
                map.put(src, pq);
            }
            map.get(src).add(dst);
        }
        dfs("JFK");
        return resList;
    }

    private void dfs(String src) {
        PriorityQueue<String> pq = map.get(src);
        //正常的深度優先搜尋步驟
        while(pq != null && !pq.isEmpty()) dfs(pq.poll());
        //當由src發出的邊均已訪問時,src就成了一個“孤點”,這時把它逆序插入
        resList.add(0,src);
    }

原題:332.重新安排行程
參考:[Java]DFS解法