重新安排行程
Leetcode 332
学习记录自代码随想录
给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
例如,行程 [“JFK”, “LGA”] 与 [“JFK”, “LGB”] 相比就更小,排序更靠前。
假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。
输入:tickets = [[“MUC”,“LHR”],[“JFK”,“MUC”],[“SFO”,“SJC”],[“LHR”,“SFO”]]
输出:[“JFK”,“MUC”,“LHR”,“SFO”,“SJC”]
输入:tickets = [[“JFK”,“SFO”],[“JFK”,“ATL”],[“SFO”,“ATL”],[“ATL”,“JFK”],[“ATL”,“SFO”]]
输出:[“JFK”,“ATL”,“JFK”,“SFO”,“ATL”,“SFO”]
解释:另一种有效的行程是 [“JFK”,“SFO”,“ATL”,“JFK”,“ATL”,“SFO”] ,但是它字典排序更大更靠后。
要点:1.回溯模板上修改一些判断条件;
2.需要开始对车票排序,之后排过序后只要找到一个方案就是所需的字母排序最小的方案;
3.检查重复的车票,有的车票会重复;
4.检查使用过的车票以及车票开头是否等于上次末尾;
方法一:
class Solution {
private:
// vector<string> path = {"JFK"};
string start = "JFK";
vector<vector<string>> result;
void backtracking(vector<vector<string>>& tickets, vector<int> used, vector<string> path){
if(path.size() == tickets.size() + 1){
result.push_back(path);
return;
}
// start = path.back();
for(int i = 0; i < tickets.size(); i++){
// 已经对车票开始排过序了,所以只要找到一个方案就是所需的字母排序最小的方案
if(result.size() > 0) break;
// 检查重复的车票,有的车票会重复
if (i > 0 && !used[i - 1] && tickets[i][0] == tickets[i - 1][0] && tickets[i][1] == tickets[i - 1][1]) {
continue;
}
// 检查使用过的车票以及车票开头是否等于上次末尾
if(used[i] == 1 || tickets[i][0] != start){
continue;
}
start = tickets[i][1];
used[i] = 1;
path.push_back(tickets[i][1]);
backtracking(tickets, used, path);
path.pop_back();
start = path.back();
used[i] = 0;
}
}
public:
vector<string> findItinerary(vector<vector<string>>& tickets){
// path.clear();
sort(tickets.begin(), tickets.end());
vector<string> path = {"JFK"};
vector<int> used(tickets.size(), 0);
backtracking(tickets, used, path);
// sort(result.begin(), result.end());
return result[0];
}
};
方法二:使用map存储机票路径
//使用map存储
class Solution{
private:
// 出发机场,<到达机场,标记机场是否使用过>
unordered_map<string, map<string, int>> targets;
// 注意此处result需要引用,不然输入的result只是为形参,不改变原来的result
bool backtracking(vector<string>& result, vector<vector<string>>& tickets){
if(result.size() == tickets.size() + 1){
return true;
}
// target需要引用以对应更改targets, const防止更改
// for(auto& target : targets[result.back()]){
for(pair<const string, int>& target : targets[result.back()]){
if(target.second > 0){
result.push_back(target.first);
target.second--;
if(backtracking(result, tickets)) return true; // 这样一找到结果就能返回
result.pop_back(); // 回溯
target.second++; // 回溯
}
}
return false;
}
public:
vector<string> findItinerary(vector<vector<string>>& tickets){
targets.clear();
// 记录映射关系,map是有序的,存储结果自动会排序,1代表没去过,0代表去过
for(const vector<string>& vec : tickets){
targets[vec[0]][vec[1]]++;
}
vector<string> result;
result.push_back("JFK");
backtracking(result, tickets);
return result;
}
};