LeetCode 332. Reconstruct Itinerary(重构行程)

50 篇文章 0 订阅
41 篇文章 0 订阅

原题网址:https://leetcode.com/problems/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 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.

这是一道经典的图论问题,本质上是欧拉路径/七桥问题/一笔画问题。

方法一:深度优先搜索,如果无法遍历全部边(机票),则回溯。

public class Solution {
    private boolean find(Map<String, List<String>> graph, List<String> itinerary, int target) {
        if (itinerary.size() == target) return true;

        String t = itinerary.get(itinerary.size()-1);
        List<String> next = graph.get(t);
        if (next == null) return false;
        for(int i=0; i<next.size(); i++) {
            itinerary.add(next.get(i));
            next.remove(i);
            if (find(graph, itinerary, target)) return true;
            next.add(i, itinerary.get(itinerary.size()-1));
            itinerary.remove(itinerary.size()-1);
        }
        return false;
    }
    public List<String> findItinerary(String[][] tickets) {
        Map<String, List<String>> graph = new HashMap<>();
        for(int i=0; i<tickets.length; i++) {
            List<String> next = graph.get(tickets[i][0]);
            if (next == null) {
                next = new ArrayList<>();
                graph.put(tickets[i][0], next);
                // set.add(tickets[i][0]);
            }
            next.add(tickets[i][1]);
        }
        for(List<String> next: graph.values()) Collections.sort(next);
        List<String> itinerary = new ArrayList<>();
        itinerary.add("JFK");
        find(graph, itinerary, tickets.length+1);
        return itinerary;
    }
}

方法二:直接应用一笔画算法。

public class Solution {
    public List<String> findItinerary(String[][] tickets) {
        Map<String, PriorityQueue<String>> graph = new HashMap<>();
        for(String[] ticket: tickets) {
            PriorityQueue<String> nexts = graph.get(ticket[0]);
            if (nexts == null) {
                nexts = new PriorityQueue<>();
                graph.put(ticket[0], nexts);
            }
            nexts.add(ticket[1]);
        }
        return eulerian(graph, "JFK");
    }
    
    private List<String> eulerian(Map<String, PriorityQueue<String>> graph, String city) {
        List<String> route = new ArrayList<>();
        route.add(city);
        PriorityQueue<String> nexts = graph.get(city);
        if (nexts == null) return route;
        while (!nexts.isEmpty()) {
            String next = nexts.remove();
            route.addAll(1, eulerian(graph, next));
        }
        return route;
    }
}

方法三:一笔画算法的递归实现(参考LeetCode的论坛文章 https://leetcode.com/discuss/84659/short-ruby-python-java-c

public class Solution {
    public List<String> findItinerary(String[][] tickets) {
        Map<String, PriorityQueue<String>> graph = new HashMap<>();
        List<String> route = new ArrayList();
        for(String[] ticket: tickets) {
            PriorityQueue<String> heap = graph.get(ticket[0]);
            if (heap == null) {
                heap = new PriorityQueue<>();
                graph.put(ticket[0], heap);
            }
            heap.add(ticket[1]);
        }
        visit(graph, route, "JFK");
        return route;
    }

    private void visit(Map<String, PriorityQueue<String>> graph, List<String> route, String airport) {
        PriorityQueue<String> next = graph.get(airport);
        while (next != null && !next.isEmpty()) visit(graph, route, next.poll());
        route.add(0, airport);
    }
}

另一种实现:

public class Solution {
    private void find(String curr, Map<String, List<String>> graph, List<String> itinerary) {
        List<String> nexts = graph.get(curr);
        while (nexts != null && !nexts.isEmpty()) {
            String next = nexts.get(0);
            nexts.remove(0);
            find(next, graph, itinerary);
        }
        itinerary.add(0, curr);
    }
    public List<String> findItinerary(String[][] tickets) {
        Map<String, List<String>> graph = new HashMap<>();
        for(String[] ticket: tickets) {
            List<String> nexts = graph.get(ticket[0]);
            if (nexts == null) {
                nexts = new ArrayList<>();
                graph.put(ticket[0], nexts);
            }
            nexts.add(ticket[1]);
        }
        for(List<String> nexts: graph.values()) Collections.sort(nexts);
        List<String> itinerary = new ArrayList<>();
        find("JFK", graph, itinerary);
        return itinerary;
    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值