力扣第332题 重新安排行程 c++ 难

题目

332. 重新安排行程

困难

相关标签

深度优先搜索   图   欧回路        

        给你一份航线列表 tickets ,其中 tickets[i] = [fromi, toi] 表示飞机出发和降落的机场地点。请你对该行程进行重新规划排序。

所有这些机票都属于一个从 JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 开始。如果存在多种有效的行程,请你按字典排序返回最小的行程组合。

  • 例如,行程 ["JFK", "LGA"] 与 ["JFK", "LGB"] 相比就更小,排序更靠前。

假定所有机票至少存在一种合理的行程。且所有的机票 必须都用一次 且 只能用一次。

示例 1:

力扣第332题 重新安排行程 c++ 难_第1张图片

输入:tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
输出:["JFK","MUC","LHR","SFO","SJC"]

示例 2:

力扣第332题 重新安排行程 c++ 难_第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

思路和解题方法

  1. 定义了一个私有方法 backtracking,用于进行航班路线的搜索。其中 ticketNum 表示航班票数,result 是当前已经搜索到的路径。在搜索过程中,如果找到了一条合法的路径,直接返回 true 结束搜索。
  2. 在搜索时,首先从 result 中最后一个机场出发,查找所有可以到达的目的地。这里采用了一个键值对嵌套的方式进行记录,其中外层的键为出发机场,内层的键为到达机场,内层的值为该机场之间可用的航班次数。因此,可以通过 targets[result[result.size() - 1]] 查找到当前机场可以到达的所有目的地,并且记录了对应的航班次数。
  3. 然后遍历所有可以到达的目的地,如果当前目的地没有被访问过(即其航班次数大于0),则将其加入到 result 中,并将该航班次数减1。同时,递归调用 backtracking 进行下一步的搜索。如果找到了合法的路径,则直接返回 true。如果当前路径不是合法的路径,则进行回溯操作,将当前目的地从 result 中移除,并将其航班次数加1,以便在后续的搜索中重新选择该目的地。
  4. 最终,在主函数 findItinerary 中,首先进行了初始化操作,清空键值对列表 targets 并记录映射关系。然后从起始机场 "JFK" 开始进行搜索,调用 backtracking 函数,直至找到一条合法的路径。最后返回最终的结果。

复杂度

        时间复杂度:

                O(N * N^N)

时间复杂度:

  • 首先,对于构建映射关系的循环操作,需要遍历全部的航班票数量,因此时间复杂度为 O(N),其中 N 是航班票的数量。
  • 其次,在 backtracking 方法中,遍历所有可以到达的目的地,每个目的地都可能进行递归调用,最多进行 N 次递归。因此,在整个搜索过程中,每个节点的扩展次数加起来约为 N,所以时间复杂度为 O(N^N)。 综合起来,整体的时间复杂度为 O(N * N^N)。

        空间复杂度

                O(N)

空间复杂度:

  • 首先,使用了一个哈希表 targets 来存储航班的映射关系,其中需要记录出发机场、到达机场和航班次数。因此,该哈希表所占用的空间为 O(N),其中 N 是航班票的数量。
  • 其次,在递归调用 backtracking 过程中,需要维护一个路径 result,其长度不会超过航班票数量 N。因此,路径所占用的空间为 O(N)。 综合起来,整体的空间复杂度为 O(N)。

c++ 代码

class Solution {
private:
    unordered_map> targets; // 存储出发机场和到达机场之间的航班次数

    /**
     * 回溯函数,用于生成航班路径
     * @param ticketNum 总的航班数量
     * @param result 当前正在生成的航班路径
     * @return 是否成功找到完整的航班路径
     */
    bool backtracking(int ticketNum, vector& result) {
        if (result.size() == ticketNum + 1) { // 航班路径中包含了所有的航班
            return true;
        }
        for (pair& target : targets[result[result.size() - 1]]) {
            if (target.second > 0) { // 判断当前到达机场的航班次数是否还有剩余
                result.push_back(target.first); // 将当前到达机场加入到航班路径中
                target.second--; // 减少当前到达机场的航班次数
                if (backtracking(ticketNum, result)) return true; // 递归调用,继续生成剩余的航班路径
                result.pop_back(); // 回溯操作,将最后添加的到达机场移出航班路径
                target.second++; // 恢复当前到达机场的航班次数,以便生成其他路径
            }
        }
        return false;
    }

public:
    /**
     * 寻找符合条件的航班路径
     * @param tickets 给定的航班信息(包含起始机场和到达机场)
     * @return 符合条件的航班路径
     */
    vector findItinerary(vector>& tickets) {
        targets.clear(); // 清空存储航班次数的映射关系
        vector result; // 存储最终的航班路径
        for (const vector& vec : tickets) {
            targets[vec[0]][vec[1]]++; // 记录起始机场和到达机场之间的航班次数
        }
        result.push_back("JFK"); // 起始机场
        backtracking(tickets.size(), result); // 生成航班路径
        return result; // 返回符合条件的航班路径
    }
};

觉得有用的话可以点点赞,支持一下。

如果愿意的话关注一下。会对你有更多的帮助。

每天都会不定时更新哦  >人<  。

你可能感兴趣的:(leetcode,回溯,数据结构,算法,leetcode,c++,回溯)