题目链接:332. 重新安排行程
给你一份航线列表 tickets
,其中 tickets[i] = [fromi, toi]
表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。
所有这些机票都属于一个从 JFK
(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK
开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。
["JFK", "LGA"]
与 ["JFK", "LGB"]
相比就更小,排序更靠前。假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。
示例 1:
输入:tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]] 输出:["JFK","MUC","LHR","SFO","SJC"]
示例 2:
输入:tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]] 输出:["JFK","ATL","JFK","SFO","ATL","SFO"] 解释:另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"] ,但是它字典排序更大更靠后。
提示:
1 <= tickets.length <= 300
tickets[i].length == 2
fromi.length == 3
toi.length == 3
fromi
和 toi
由大写英文字母组成fromi != toi
文章讲解:代码随想录
思路:本题考虑到对有向图进行深度优先搜索得出答案,同时涉及到车票数量的问题,可以考虑使用回溯法。首先构建一个出发地、目的地和车票数量之间的映射,使用 Map
回溯分析:
/**
* @param {string[][]} tickets
* @return {string[]}
*/
var findItinerary = function(tickets) {
tickets.sort(); // 对车票排序
// 构建映射关系,出发地: { 目的地: 车票数量 }
const map = {};
tickets.forEach(item => {
map[item[0]] ? (map[item[0]][item[1]] ? map[item[0]][item[1]]++ : map[item[0]][item[1]] = 1) : map[item[0]] = { [item[1]]: 1 };
});
let res = []; // 保存结果
const path = ["JFK"]; // 路径
const backtracking = function () {
// 路径长度等于车票数量加1,说明收集到了1个结果,因为原数组已排序,第1个结果就是本题的结果
if (path.length === tickets.length + 1) {
res = [...path]; // 记录到结果中
return true; // 找到符合条件的路径,返回 true
}
const arr = map[path[path.length - 1]]; // 获取下一个目的地
for (let i in arr) {
// 当有车票时进行操作
if (arr[i] > 0) {
path.push(i); // 记录路径
arr[i]--; // 更新车票数量
// 向下查找
if (backtracking()) {
return true; // 找到符合条件的路径,返回 true
}
// 回溯
path.pop();
arr[i]++;
}
};
return false;
}
backtracking();
return res;
};
回溯法本质就是一个暴力的深度优先搜索算法,递归的遍历中带有回溯,不可能出现结果的部分应该剪枝。