这一题并不是我个人很喜欢的题目类型。最优解基本就是特定的算法,知道就能过,不知道也不是你能短时间里想出来的解决方案。这题就是欧拉路径的题目,给定起点和所有边的信息,在不重复的情况下走完全图。
https://ikely.me/2015/06/28/%E6%AC%A7%E6%8B%89%E8%B7%AF/
https://www.cnblogs.com/KasenBob/p/9985398.html
第一篇文章里的第二种算法以及第二篇文章都是在讲述这一类题目的最优解Hierholzer算法。其实就是一个先建图再dfs遍历图的一个标准的过程。你可以认为这是一个自下而上的遍历。先dfs遍历子节点,然后遍历完之后再把自己放进结果链表的头。就这样从后往前建立结果。根据这个算法,可以得到代码如下:
public List<String> findItinerary(List<List<String>> tickets) {
Map<String, PriorityQueue<String>> graph = new HashMap<>();
for (List<String> ticket : tickets) {
graph.computeIfAbsent(ticket.get(0), k -> new PriorityQueue<>()).add(ticket.get(1));
}
LinkedList<String> result = new LinkedList<>();
dfs(graph, "JFK", result);
return result;
}
public void dfs(Map<String, PriorityQueue<String>> graph, String loc, LinkedList<String> result) {
if (graph.containsKey(loc)) {
PriorityQueue<String> que = graph.get(loc);
while(!que.isEmpty()) {
dfs(graph, que.poll(), result);
}
}
result.addFirst(loc);
}
这里之所以用到了PriorityQueue,是因为要输出smallest lexical order的结果。不然随便一个queue都可以。
另外再给一套代码,算法是一致的。但是用了循环代替递归。
public List<String> findItinerary(List<List<String>> tickets) {
Map<String, PriorityQueue<String>> graph = new HashMap<>();
for (List<String> ticket : tickets) {
graph.computeIfAbsent(ticket.get(0), k -> new PriorityQueue<>()).add(ticket.get(1));
}
LinkedList<String> result = new LinkedList<>();
Stack<String> dfsStk = new Stack<String>();
dfsStk.push("JFK");
while (!dfsStk.isEmpty()) {
String curNode = dfsStk.peek();
PriorityQueue<String> nextNodes = graph.get(curNode);
if (nextNodes == null || nextNodes.isEmpty()) {
dfsStk.pop();
result.addFirst(curNode);
} else {
dfsStk.push(nextNodes.poll());
}
}
return result;
}