Reconstruct Itinerary

利用深度优先搜索解决LeetCode中的332题,将机票转化为有向图,寻找字典序最小的欧拉路径。题目涉及图论和DFS算法,通过构建图并记录边的数量,遍历所有可能的路径来找到满足条件的行程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Leetcode-Algorithm-Graph-332

题目:
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 .
(给定一个飞机票的列表,通过起始机场[from, to]来表示。根据机票列表重新构造出整个旅行路线。所有机票都是属于一个从JFK出发的人的,因此旅程必须是从JFK开始的。)
注意:
若存在多个旅行路线,按照字典序返回最小的那一个。

例子:

给定: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”],但是由于字典序的关系,返回的是[“JFK”,”ATL”,”JFK”,”SFO”,”ATL”,”SFO”]。)


题解:
方法:(DFS-深度优先搜索)
根据题意,需要通过飞机票确定旅行路线,所以每一张飞机票都需要使用。因此,若以机场为顶点,机票为机场间的有向边,我们可以构造出一个有向图,而问题就转换为找到一条路径能够经过所有的边一次且仅一次,也相当于找到有向图中字典序最小的一条欧拉路径。因此我们在构造一个图的时候必须记录每一条边,通过测试用例知道会存在重复的边,因此需要记录边的数目以便确定是否已经遍历完所有的边。所以代码中使用unordered_map以及map的组合来记录所有变,由于map中元素是根据key来排序的,因此同时满足我们需要根据字典序来遍历的需求。构造好图后通过DFS来遍历整个图,记录DFS在通过某条路径走到最后时(即遍历的下一条边之前已经遍历过)是否都经过所有的边,不是,返回上一层从别的路径开始遍历,是,则返回到顶层递归。在遍历的过程中一直记录着路径中的所有顶点。

class Solution {
public:
    vector<string> findItinerary(vector<pair<string, string>> tickets) {
        unordered_map<string, map<string, int>> graph;

        //通过unordered_map以及map的组合记录每一张机票代表的边。
        //因为最后的路线要按照字典序,因此在构图时就需要按字典序排好。
        for (auto ticket : tickets) {
            graph[ticket.first][ticket.second] += 1;
        }

        vector<string> result;
        result.push_back("JFK");
        int count = 0;
        traverse(graph, result, "JFK", count, tickets.size());

        return result;
    }

    //通过DFS来遍历整个图,在遍历过程中记录以遍历的边的数量以此为
    //是否需要继续遍历的标准并作相应的处理。
    void traverse(unordered_map<string, map<string, int>> &graph,
        vector<string> &result,
        string org, int &count, int full) {
        map<string, int>::iterator iter = graph[org].begin();
        while (iter != graph[org].end()) {
            string des = iter->first;
            int linkCount = iter->second;
            if (linkCount != 0) {
                iter->second -= 1;
                result.push_back(des);
                traverse(graph, result, des, ++count, full);
                if (count == full)
                    break;
                else {
                    result.pop_back();
                    --count;
                    iter->second += 1;
                }
            }

            ++iter;
        }
    }
};
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值