问题描述
我一开始的做法:
class Solution {
ArrayList<String> result = new ArrayList<>();
ArrayList<String> path = new ArrayList<>();
boolean[] used;
public List<String> findItinerary(List<List<String>> tickets) {
if (tickets.size() == 0) {
return result;
}
used = new boolean[tickets.size()];
//为空时添加第一个元素并开始回溯
for (int i = 0; i < tickets.size(); i++) {
if (tickets.get(i).get(0).equals("JFK")) {
path.add(tickets.get(i).get(0));
path.add(tickets.get(i).get(1));
used[i] = true;
backtracing(tickets);
used[i] = false;
path.removeLast();
path.removeLast();
}
}
return result;
}
public void backtracing(List<List<String>> tickets) {
if (path.size() == tickets.size() + 1) {
//System.out.println(path.toString());
if (result.isEmpty()) {
result = new ArrayList<>(path);
} else{
for (int i = 0; i < path.size(); i++) {
if (path.get(i).compareTo(result.get(i)) < 0) {
result = new ArrayList<>(path);
break;
}
if (path.get(i).compareTo(result.get(i)) > 0) {
break;
}
}
}
}
int addIndex = -1;
//一次添加一个元素
for (int i = 0; i < tickets.size(); i++) {
if (used[i]) {
continue;
}
if (tickets.get(i).get(0).equals(path.get(path.size() - 1))) {
path.add(tickets.get(i).get(1));
used[i] = true;
backtracing(tickets);
used[i] = false;
path.removeLast();
}
}
}
}
可能能得到正确的结果,但是会超时,因为每次都是一个完全的遍历,O(n^tickets.size())的时间复杂度
改进的地方:对机票的信息进行预先的排序,同时用哈希表存储,这样可以降低搜索的复杂度从而提高效率
使用回溯的思想:
一个需要注意的地方:这里的回溯返回值为boolean
**基于list的回溯:**预先对tickets进行排序,然后就是简单的回溯,但是在最新的测试样例里,还是会超时
class Solution {
LinkedList<String> result = new LinkedList<>();
LinkedList<String> path = new LinkedList<>();
boolean[] used;
public List<String> findItinerary(List<List<String>> tickets) {
Collections.sort(tickets, (a, b) -> a.get(1).compareTo(b.get(1)));
used = new boolean[tickets.size()];
path.add("JFK");
backtracing((ArrayList)tickets);
return result;
}
public boolean backtracing(ArrayList<List<String>> tickets) {
if (path.size() == tickets.size() + 1) {
result = new LinkedList<>(path);
return true;
}
for (int i = 0; i < tickets.size(); i++) {
if (!used[i] && tickets.get(i).get(0).equals(path.getLast())) {
path.add(tickets.get(i).get(1));
used[i] = true;
if (backtracing(tickets)) {
return true;
}
//回溯
used[i] = false;
path.removeLast();
}
}
return false;
}
}
基于map的回溯:
用treemap来存储同一个起始站的机票,对终点进行排序,这样找到的第一组路径就是最终需要的序列最小的路径
class Solution {
Map<String, Map<String, Integer>> record;
LinkedList<String> res;
public List<String> findItinerary(List<List<String>> tickets) {
record = new HashMap<>();
res = new LinkedList<>();
//初始化record
for (List<String> ticket : tickets) {
//temp存的<目的地,票数>
Map<String, Integer> temp;
String startSite = ticket.get(0); //当前机票出发地
String destination = ticket.get(1); //当前机票终点站
if (record.containsKey(startSite)) {
temp = record.get(startSite);
temp.put(destination, temp.getOrDefault(destination, 0) + 1);
} else {
temp = new TreeMap<>();
temp.put(destination, 1);
}
record.put(startSite, temp);
}
res.add("JFK");
backtracing(tickets);
return res;
}
public boolean backtracing(List<List<String>> tickets) {
if (res.size() == tickets.size() + 1) {
return true;
}
if (record.containsKey(res.getLast())) {
for (Map.Entry<String, Integer> entry : record.get(res.getLast()).entrySet()) {
int count = entry.getValue();
if (count > 0) {
res.add(entry.getKey());
entry.setValue(count - 1);
if(backtracing(tickets)) {
return true;
}
entry.setValue(count);
res.removeLast();
}
}
}
return false;
}
}