⭐算法OJ⭐重建行程【哈密尔顿路径】(C++ 实现)Reconstruct Itinerary

You are given a list of airline tickets where tickets[i] = [from_i, to_i] represent the departure and the arrival airports of one flight. Reconstruct the itinerary in order and return it.

All of the tickets belong to a man who departs from “JFK”, thus, the itinerary must begin with “JFK”. If there are multiple valid itineraries, you should return the itinerary that has the smallest lexical order when read as a single string.

For example, the itinerary ["JFK", "LGA"] has a smaller lexical order than ["JFK", "LGB"].
You may assume all tickets form at least one valid itinerary. You must use all the tickets once and only once.

Example 1:
在这里插入图片描述

Input: tickets = [["MUC","LHR"],["JFK","MUC"],["SFO","SJC"],["LHR","SFO"]]
Output: ["JFK","MUC","LHR","SFO","SJC"]

Example 2:
在这里插入图片描述

Input: tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
Output: ["JFK","ATL","JFK","SFO","ATL","SFO"]
Explanation: Another possible reconstruction is ["JFK","SFO","ATL","JFK","ATL","SFO"] but it is larger in lexical order.

问题描述

给定一组机票(出发地,目的地),从"JFK"出发,按字典序最小的顺序重建行程。所有机票必须且只能使用一次。

解法思路

  • 使用 Hierholzer 算法来寻找欧拉路径:
    • 构建图的邻接表,使用优先队列(最小堆)来存储邻接节点
    • 从起点"JFK"开始进行深度优先搜索(DFS)
    • 每次访问一个节点时,将其从图中移除
    • 当某个节点的邻接列表为空时,将其加入结果列表
    • 最后将结果列表反转即为所求行程

C++ 实现

#include <vector>
#include <string>
#include <unordered_map>
#include <queue>
#include <algorithm>

using namespace std;

vector<string> findItinerary(vector<vector<string>>& tickets) {
    // 构建图的邻接表,使用优先队列(最小堆)来存储邻接节点
    unordered_map<string, priority_queue<string, vector<string>, greater<string>>> graph;
    
    for (const auto& ticket : tickets) {
        graph[ticket[0]].push(ticket[1]);
    }
    
    vector<string> itinerary;
    dfs("JFK", graph, itinerary);
    reverse(itinerary.begin(), itinerary.end());
    return itinerary;
}

void dfs(const string& node, 
         unordered_map<string, priority_queue<string, vector<string>, greater<string>>>& graph,
         vector<string>& itinerary) {
    // 访问所有邻接节点
    while (!graph[node].empty()) {
        string next_node = graph[node].top();
        graph[node].pop();
        dfs(next_node, graph, itinerary);
    }
    // 当前节点没有出边时加入结果
    itinerary.push_back(node);
}

迭代实现版本

#include <vector>
#include <string>
#include <unordered_map>
#include <stack>
#include <algorithm>

using namespace std;

vector<string> findItinerary(vector<vector<string>>& tickets) {
    // 构建图的邻接表,按字典序逆序存储以便从尾部取元素
    unordered_map<string, vector<string>> graph;
    for (const auto& ticket : tickets) {
        graph[ticket[0]].push_back(ticket[1]);
    }
    
    // 对邻接表进行排序,然后反转,以便从尾部取最小字典序
    for (auto& [src, dsts] : graph) {
        sort(dsts.begin(), dsts.end(), greater<string>());
    }
    
    vector<string> itinerary;
    stack<string> stk;
    stk.push("JFK");
    
    while (!stk.empty()) {
        string node = stk.top();
        if (!graph[node].empty()) {
            string next_node = graph[node].back();
            graph[node].pop_back();
            stk.push(next_node);
        } else {
            itinerary.push_back(node);
            stk.pop();
        }
    }
    
    reverse(itinerary.begin(), itinerary.end());
    return itinerary;
}

复杂度分析

  • 时间复杂度: O ( E l o g E ) O(E log E) O(ElogE),其中 E E E是边的数量(机票数)。构建图时需要排序邻接表。
  • 空间复杂度: O ( E ) O(E) O(E),用于存储图的邻接表。

关键点说明

  • 使用优先队列(最小堆)确保每次取出字典序最小的目的地
  • DFS后序处理确保正确构建欧拉路径
  • 结果需要反转是因为我们是后序添加节点
  • 迭代版本使用显式栈来避免递归深度问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值