[LeetCode]Reconstruct Itinerary

题目描述:

LeetCode 332. Reconstruct Itinerary

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:

  1. 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"].
  2. All airports are represented by three capital letters (IATA code).
  3. You may assume all tickets may 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开始。

注意:

  1. 如果存在多重有效的行程,你应当返回字典序最小的那个。例如,行程["JFK", "LGA"]的字典序比["JFK", "LGB"]要小。
  2. 所有的机场用3个大写字母表示(IATA编码)。
  3. 你可以假设所有的机票均至少包含一条有效的行程。

测试用例如题目描述。

解题思路:

解法I 深度优先搜索(DFS):

从出发机场开始,按照到达机场的字典序递归搜索

在搜索过程中删除已经访问过的机票

将到达机场分为两类:子行程中包含出发机场的记为left,不含出发机场的记为right

返回时left排在right之前,详见代码。

Python代码:

class Solution(object):
    def findItinerary(self, tickets):
        """
        :type tickets: List[List[str]]
        :rtype: List[str]
        """
        routes = collections.defaultdict(list)
        for s, e in tickets:
            routes[s].append(e)
        def solve(start):
            left, right = [], []
            for end in sorted(routes[start]):
                if end not in routes[start]:
                    continue
                routes[start].remove(end)
                subroutes = solve(end)
                if start in subroutes:
                    left += subroutes
                else:
                    right += subroutes
            return [start] + left + right
        return solve("JFK")

解法II 欧拉通路(Eulerian path):

参考链接:https://leetcode.com/discuss/84659/short-ruby-python-java-c

将机场视为顶点,机票看做有向边,可以构成一个有向图。

通过图(无向图或有向图)中所有边且每边仅通过一次的通路称为欧拉通路,相应的回路称为欧拉回路。具有欧拉回路的图称为欧拉图(Euler Graph),具有欧拉通路而无欧拉回路的图称为半欧拉图。

因此题目的实质就是从JFK顶点出发寻找欧拉通路,可以利用Hierholzer算法。

Python代码:

class Solution(object):
    def findItinerary(self, tickets):
        """
        :type tickets: List[List[str]]
        :rtype: List[str]
        """
        targets = collections.defaultdict(list)
        for a, b in sorted(tickets)[::-1]:
            targets[a] += b,
        route = []
        def visit(airport):
            while targets[airport]:
                visit(targets[airport].pop())
            route.append(airport)
        visit('JFK')
        return route[::-1]

 

本文链接:http://bookshadow.com/weblog/2016/02/05/leetcode-reconstruct-itinerary/
请尊重作者的劳动成果,转载请注明出处!书影博客保留对文章的所有权利。

如果您喜欢这篇博文,欢迎您捐赠书影博客: ,查看支付宝二维码

Pingbacks已关闭。

评论
  1. Candice Candice 发布于 2016年2月9日 09:19 #

    可以解释一下下面这段代码的含义吗?谢谢
    for end in sorted(routes[start]):
    if end not in routes[start]:
    continue

  2. 在线疯狂 在线疯狂 发布于 2016年2月10日 11:33 #

    在遍历sorted(routes[start])过程中,递归调用的子过程可能已经访问并从routes[start]中移除元素,所以添加一个if语句判断下end是否还在routes[start]中。

张贴您的评论