【算法】【Graph】Reconstruct Itinerary

Difficulty: Medium

Description

Given a list of airline tickets represented by pairs of departure and arrival airports [from, to], reconstruct the itinerary(线路) in order. All of the tickets belong to a man who departs from JFK. Thus, the itinerary must begin with JFK.

Note:

  1. 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"].

  2. All airports are represented by three capital letters (IATA code).

  3. You may assume all tickets form at least one valid itinerary.

Example 1:
tickets = [["MUC", "LHR"], ["JFK", "MUC"], ["SFO", "SJC"], ["LHR", "SFO"]]
Return ["JFK", "MUC", "LHR", "SFO", "SJC"].

Example 2:
tickets = [["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]
Return ["JFK","ATL","JFK","SFO","ATL","SFO"].
Another possible reconstruction is ["JFK","SFO","ATL","JFK","ATL","SFO"]. But it is larger in lexical order.

Solution

思路

一开始我以为是简单的DFS算法,但发现Submission怎样都无法通过。后来才知道,原来题中“valid itinerary”是指,这个人所有的tickets必须连成一条完整的线,类似于一笔画,但首尾不一定要相连。

那该怎么完成这个一笔画呢。一个简单的解决办法是用后序遍历,再把遍历的这些地点倒序输出,即完成。

拿Discuss高票回答的例子来说,若输出[JFK, A, C, D, A, B, C, JFK, D]则是错误的,因为这不能连成一笔画,这个人不可能从A凭空消失,出现在D并继续飞往B的。

<code>[JFK, A], [A, C], [C, D], [D, A], [D, B], [B, C], [C, JFK], [JFK, D]</code>

正确的做法之一是,先后拓展了[JFK, A, C, D, A]后,发现没路了,写出A(push进vector<string> out 中,此时out中的元素为[A]),回到D,再依次进入[B, C, JFK, D],没路了,写出D,回到JFK,发现也没路了,写出JFK,如此类推。

最后out = [A, D, JFK, C, B, D, C, A, JFK]。返回倒序的out数组,完成。

代码

class Solution {
public:
    vector<string> findItinerary(vector<pair<string, string>> tickets) {
        for (auto t : tickets) {
            route[t.first].insert(t.second);
        }
        dfs("JFK");
        return vector<string>(output.rbegin(), output.rend());

    }

private:
    unordered_map<string, multiset<string>> route;
    vector<string> output;

    void dfs(string src) {
        while (route[src].size()) {
            auto p = route[src].begin();
            string dst = *p;
            route[src].erase(p);
            dfs(dst);
        }
        output.push_back(src);
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Dijkstra算法是一种用于解决单源最短路径问题的贪心算法,它可以用C语言实现。在实现Dijkstra算法时,需要使用图来表示问题,并使用优先队列来维护当前最短路径的节点。 在C语言中,可以使用结构体来表示图中的节点和边,例如: ``` typedef struct { int dest; // 目标节点 int weight; // 边的权重 } Edge; typedef struct { Edge* edges; // 边的数组 int numEdges; // 边的数量 } Node; typedef struct { Node* nodes; // 节点的数组 int numNodes; // 节点的数量 } Graph; ``` 在实现Dijkstra算法时,需要使用一个数组来记录每个节点的最短路径长度和前驱节点,例如: ``` typedef struct { int dist; // 最短路径长度 int prev; // 前驱节点 bool visited; // 是否已访问 } DijkstraData; ``` 然后,可以使用优先队列来维护当前最短路径的节点,例如: ``` typedef struct { int node; // 节点编号 int dist; // 最短路径长度 } PQNode; typedef struct { PQNode* nodes; // 节点的数组 int size; // 队列的大小 int capacity; // 队列的容量 } PriorityQueue; ``` 最后,可以使用以下代码来实现Dijkstra算法: ``` void dijkstra(Graph* graph, int start, DijkstraData* data) { PriorityQueue pq; pq.nodes = (PQNode*) malloc(sizeof(PQNode) * graph->numNodes); pq.size = ; pq.capacity = graph->numNodes; for (int i = ; i < graph->numNodes; i++) { data[i].dist = INT_MAX; data[i].prev = -1; data[i].visited = false; } data[start].dist = ; PQNode startNode = { start, }; pqPush(&pq, startNode); while (!pqIsEmpty(&pq)) { PQNode node = pqPop(&pq); if (data[node.node].visited) { continue; } data[node.node].visited = true; for (int i = ; i < graph->nodes[node.node].numEdges; i++) { Edge edge = graph->nodes[node.node].edges[i]; int dest = edge.dest; int weight = edge.weight; if (data[dest].visited) { continue; } int newDist = data[node.node].dist + weight; if (newDist < data[dest].dist) { data[dest].dist = newDist; data[dest].prev = node.node; PQNode destNode = { dest, newDist }; pqPush(&pq, destNode); } } } free(pq.nodes); } ``` 其中,pqPush和pqPop函数可以使用堆来实现。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值