332. 重新安排行程

给定一个机票的字符串二维数组 [from, to],子数组中的两个成员分别表示飞机出发和降落的机场地点,对该行程进行重新规划排序。所有这些机票都属于一个从JFK(肯尼迪国际机场)出发的先生,所以该行程必须从 JFK 出发。

说明:

  1. 如果存在多种有效的行程,你可以按字符自然排序返回最小的行程组合。例如,行程 ["JFK", "LGA"] 与 ["JFK", "LGB"] 相比就更小,排序更靠前
  2. 所有的机场都用三个大写字母表示(机场代码)。
  3. 假定所有机票至少存在一种合理的行程。

示例 1:

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

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

示例 2:

输入:[["JFK","SFO"],["JFK","ATL"],["SFO","ATL"],["ATL","JFK"],["ATL","SFO"]]

输出: ["JFK","ATL","JFK","SFO","ATL","SFO"]
解释: 另一种有效的行程是 ["JFK","SFO","ATL","JFK","ATL","SFO"]。但是它自然排序更大更靠后。

 

思路:这个题目实际上是欧拉路径问题(一笔画问题):

概念科普:

若一个图为欧拉图或半欧拉图都可以通过一笔画遍历。

通过图(有向图或无向图)中的所有边且每一条边仅通过一次的通路称为欧拉通路,若此通路为回路则称为欧拉回路

具有欧拉回路的图称为欧拉图,具有欧拉通路而无欧拉回路的图称为半欧拉图

dfs来解决:

1、采用邻接表来表示有向图,但是要注意两个机场间可能有多张机票,所有还要多一个计数。

抽象成一个map<string, map<string, int> > &m,里面存每一个顶点的后继顶点,int是机票数。

2、由于题目要求按照字母顺序排序,所以用map替代unordered_map, unordered_map是哈希表,map是红黑树,输出有序的。

unordered_map查找时间复杂度O(1),map查找时间复杂度O(logn)。这里牺牲查找时间换输出有序功能。

3、设置标记数组,如果该行程没有机票剩余,直接跳过。

4、如果已经找到第一个字典序结果,直接返回,避免继续for循环,re被后面的字典序较大的结果覆盖。

class Solution {
public:
    vector<string>re;

    void dfs(vector<string> &temp, map<string, map<string, int> > &m, map<string, map<string, int> > &v, int n){
        if(temp.size()==n){
            re=temp;
            return;
        }
        for(auto x: m[temp.back()]){
            string stop=x.first;//当前行程的终点站
            //说明所有机票用完了
            if(v[temp.back()][stop]==x.second)  continue;
            v[temp.back()][stop]++;
            temp.push_back(stop);
            dfs(temp, m , v, n);
            temp.pop_back();
            v[temp.back()][stop]--;
            //如果已经找到一个结果,直接返回,避免for循环到最后,re被后面的字典序较大的结果覆盖
            if(re.size()==n) return;
        }
    }

    vector<string> findItinerary(vector<vector<string>>& tickets) {
        //两个机场间可能有多张机票,所以value用int来计数
        //map保证value有序,可以保证第一个搜索结果即为最终结果。unordered_map是哈希表,map是红黑树,输出有序的
        map<string, map<string, int> >m, v;//v是标记数组
        for(auto x: tickets){//初始化m
            m[x[0]][x[1]]++;
        }
        vector<string>temp;
        temp.push_back("JFK");
        dfs(temp, m, v, tickets.size()+1);
        return re;
    }
};

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值