Leetcode 332. Reconstruct Itinerary
来源:互联网 发布:windows显示后缀名 编辑:程序博客网 时间:2024/06/08 16:58
332. Reconstruct Itinerary
Total Accepted: 19256 Total Submissions: 71899 Difficulty: MediumGiven 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:
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.
思路:
DFS。
一开始想着用prorityQueue存着每个机场可以到达的点,然后遍历一遍,之后直接删,这样就可可以保证顺序。直到碰到这个test case:
Input:[["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]]
Output:["JFK","KUL"]
Expected:["JFK","NRT","JFK","KUL"]
也就是说,先到了KUL,然后删了KUL,然后就不对了。应该是去NRT然后最后KUL。也就是说算法必须智能的恢复数据。那么肯定就是dfs + backtracking了。一般DFS是用于输出所有可能性,于是先写了一个标准的DFS,把所有满足长度的结果存起来,然后输出result中的第一个结果。注意的地方是这里不能用prioritQueue了,因为每次我们遍历next 机场,完了之后还要相应复位。如果用priorityQueue,那么add之后位置就不确定了。可以用arrayList保存然后sort这样保证第一个结果一定是lexical order满足的。
public class Solution { // MLE List<List<String>> res = new ArrayList<List<String>>(); public List<String> findItinerary(String[][] tickets) { Map<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>(); for(int i = 0; i < tickets.length; i++){ String[] item = tickets[i]; if(!map.containsKey(item[0])){ map.put(item[0], new ArrayList<String>()); } map.get(item[0]).add(item[1]); } for(ArrayList<String> al : map.values()) Collections.sort(al); List<String> path = new ArrayList<String>(); path.add("JFK"); dfs(map, path, tickets.length + 1); return res.get(0); } public void dfs(Map<String, ArrayList<String>> map, List<String> path, int tarLen){ if(path.size() == tarLen){ res.add(new ArrayList<String>(path)); return; // 一定要新建一个!!debug 半小时 } String cur = path.get(path.size() - 1); ArrayList<String> dest= map.get(cur); for(int i = 0; dest != null && i < dest.size(); i++){ String next = dest.get(i); path.add(next); dest.remove(i); dfs(map, path, tarLen); path.remove(path.size() - 1); dest.add(i, next); } }}// [["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]] 访问K,回溯,访问N J 又要访问K
提示MLE。好吧,那剪枝一下,第一个满足条件的输出就行了。这样DFS就不能再是void了,因为在每个call的时候,需要知道子call是不是搞定了,搞定就不用再call了。
改成返回boolean就好。
public class Solution { // 14ms public List<String> findItinerary(String[][] tickets) { Map<String, ArrayList<String>> map = new HashMap<String, ArrayList<String>>(); for(int i = 0; i < tickets.length; i++){ String[] item = tickets[i]; if(!map.containsKey(item[0])){ map.put(item[0], new ArrayList<String>()); } map.get(item[0]).add(item[1]); } for(ArrayList<String> al : map.values()) Collections.sort(al); List<String> path = new ArrayList<String>(); path.add("JFK"); dfs(map, path, tickets.length + 1); return path; } public boolean dfs(Map<String, ArrayList<String>> map, List<String> path, int tarLen){ if(path.size() == tarLen){ return true; } String cur = path.get(path.size() - 1); ArrayList<String> dest= map.get(cur); for(int i = 0; dest != null && i < dest.size(); i++){ String next = dest.get(i); path.add(next); dest.remove(i); if(dfs(map, path, tarLen)) return true; path.remove(path.size() - 1); dest.add(i, next); } return false; }}// [["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]] 访问K,回溯,访问N J 又要访问K
网上还有更快的解法:
说是拓补排序。拓补排序一般两种,一种是入度为0的点用队列存,然后取点,修改其他点的入度,若为0入队;一种是出度为0,输出的顺序刚好相反。
这题其实是有环的,为啥使用拓补排序老实说没想通。什么欧拉回路。。不知所云。代码是这样的,的确快:
public class Solution{ // 8msHashMap<String, PriorityQueue<String>> map = new HashMap<String, PriorityQueue<String>>();LinkedList<String> result = new LinkedList<String>(); public List<String> findItinerary(String[][] tickets) {for (String[] ticket : tickets) {if (!map.containsKey(ticket[0])) {PriorityQueue<String> q = new PriorityQueue<String>();map.put(ticket[0], q);}map.get(ticket[0]).offer(ticket[1]);} dfs("JFK");return result;} public void dfs(String s) {PriorityQueue<String> q = map.get(s); while (q != null && !q.isEmpty()) {dfs(q.poll());} result.addFirst(s);}}
先遍历所有next机场,并删除,当前节点被addFirst当且仅当所有的next 机场都被访问过并删除。
[["JFK","KUL"],["JFK","NRT"],["NRT","JFK"]]
先JFK, 访问K和N,K没有next,[K],
然后访问N, N有J。访问J,访问N的时候N已经从J的NEXT删除了。这时候J没有next [J, K]
然后回到N,输出N [N J K]
然后回到J,输出J [J N J K]
- *[LeetCode]332. Reconstruct Itinerary
- leetcode 332. Reconstruct Itinerary
- LeetCode *** 332. Reconstruct Itinerary
- LeetCode 332. Reconstruct Itinerary
- leetcode 332. Reconstruct Itinerary
- [leetcode] 332. Reconstruct Itinerary
- Leetcode 332. Reconstruct Itinerary
- Leetcode 332. Reconstruct Itinerary
- Leetcode 332. Reconstruct Itinerary
- [LeetCode]332. Reconstruct Itinerary
- Leetcode: 332.Reconstruct Itinerary
- leetcode:332. Reconstruct Itinerary
- LeetCode 332. Reconstruct Itinerary
- [leetcode]332. Reconstruct Itinerary
- [LeetCode] 332. Reconstruct Itinerary
- leetcode 332. Reconstruct Itinerary
- [LeetCode]332. Reconstruct Itinerary
- LeetCode 332. Reconstruct Itinerary【medium】
- A:LinkedList实现了List接口; B: AbstractSet实现了Set接口; C: HashSet继承自AbstractSet基类; D: WeakMap继承自 AbstractMap
- final 不能修饰抽象类 方法可以被重载 但不能被重写
- 探究c++对象模型之data语义学(一)
- Android LinearLayout属性
- 多重边框 不用嵌套的多重边框写法
- Leetcode 332. Reconstruct Itinerary
- 51Nod-1464-半回文
- MySQL启动不了,无法启动MySQL服务
- JDK工具(1) jps
- Hard 380题 Insert Delete GetRandom O(1)
- Ubuntu下显卡管理
- javascript判断浏览器和终端类型,js如何区分手机、电脑终端和浏览器
- leetcode 1 Two Sum 两数之和
- java 静态代码块、静态变量、成员变量、构造代码块、构造方法的执行顺序