• Leetcode 332 重新安排行程(欧拉路径 Hierholzer算法)


    一些预备知识:

    • 欧拉路径

      如果在一张图中,可以从一点出发遍历所有的边,那么遍历过程中的这条路径就叫做欧拉路径。如果这条路径是闭合的,那就称为欧拉回路
      简单地说,如果一张图可以被“一笔画”,那么“一笔画”的那个轨迹就叫做欧拉路径

    • 欧拉图判定定理:

      含有欧拉回路的图称为欧拉图,含有欧拉路径的图称为半欧拉图。
      无向图中,如果所有顶点的度数都为偶数,则为欧拉图;如果有两个顶点的度数为奇数,其他的为偶数,则为半欧拉图。
      有向图中,如果所有顶点的入度等于出度,那么就是欧拉图;如果有两个顶点的入度不等于出度,其他的节点入度等于初读,则为半欧拉图。

      如果在一张图中,可以从一点出发遍历所有的边,那么遍历过程中的这条路径就叫做欧拉路径。如果这条路径是闭合的,那就称为欧拉回路
      简单地说,如果一张图可以被“一笔画”,那么“一笔画”的那个轨迹就叫做欧拉路径。

    • Hierholzer算法:

      解决的问题:给出一个有向图,且为欧拉图,求欧拉回路。

      算法流程:

      1. 选择任一顶点为起点,遍历所有相邻边。
      2. 深度搜索,访问相邻顶点。将经过的边都删除(标记一下就可以了)。
      3. 如果当前顶点没有相邻边,则将顶点入栈。
      4. 栈中的顶点倒序输出,就是从起点出发的欧拉回路。

       性质一:如果该图为欧拉图,则栈底的必定为起点。如果该图为半欧拉图,则栈底部存储的是与起点不同的另外一个奇度数顶点

       性质二:如果该图为欧拉图(/半欧拉图),则栈中的自底到顶第 [公式] 个顶点就是欧拉回路(/欧拉路径)上的第 [公式] 个顶点。

    题目描述:

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

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

      根据上述要求梳理出一个字典序较小的欧拉路径

    题解:

      要注意的这题是有重边的,因此边的标记就不能用普通的01标记了。比较优雅的写法是用unordered_map嵌套一个map来构建邻接矩阵。map内部是有序的,这样在遍历的时候自然会优先遍历到字典序小的车站。之后套一下Hierholzer求出欧拉路径就好了。

    AC代码:

    贴两个吧,第一个是借鉴了别人的代码,优雅了很多(嵌套map,一些遍历之类的)

    第二个是自己手搓的,没有灵活的用好map的嵌套,还人为的排序了,多费了不少。

    class Solution {
    public:
        // typedef map内部为升序
        typedef unordered_map<string,map<string,int>> adjacent;
        vector<string> ans;
        void euler(adjacent& adj,string now)
        {
            
            // map 遍历 加上 & 的化 对conut的修改 会直接影响到 adj[now][next]
            for(auto & [next,count] : adj[now])
            {
                if(count >= 1)
                {
                    // adj[now][next]--;
                    count--;
                    euler(adj,next);
                }
            }
            ans.push_back(now);
        }
        vector<string> findItinerary(vector<vector<string>>& tickets) {
            // 熟悉一下迭代的遍历方式  摒弃之前的习惯
            // map unorder_map灵活运用
            // 邻接矩 邻接表的使用
            // build_map
            adjacent adj;
            // 优美
            for(auto & t:tickets)
            {
                adj[t[0]][t[1]]++;
            }
            ans.clear();
            euler(adj,"JFK");
            reverse(ans.begin(),ans.end());
            return ans;
        }
      
    };
    class Solution {
    public:
    //TOPO
    // str -> int
    // int -> str
        int string_int(string s)
        {
            if(mp_str.find(s) != mp_str.end()) return mp_str[s];
            int id = mp_str.size();
            mp_str[s] = id;
            mp_int[id] = s;
            return id;
        }
    
        void euler(int pos)
        {
            int Len = edge[pos].size();
            sort(edge[pos].begin(),edge[pos].end());
            for(int i=0;i<Len;i++)
            {
                string next = edge[pos][i];
                if(vis[pos][mp_str[next]] >=1)
                {
                    vis[pos][mp_str[next]]--;
                    euler(mp_str[next]);
                }
            }
            ans.push_back(mp_int[pos]);
        }
        vector<string> findItinerary(vector<vector<string>>& tickets) {
            int Len = tickets.size();
            // build_map
            memset(vis,sizeof(vis),0);
            for(int i=0;i<Len;i++)
            {
                int from = string_int(tickets[i][0]);
                int to = string_int(tickets[i][1]);
                edge[from].push_back(tickets[i][1]);
                vis[from][to]++;
            }
            int city_counts = mp_str.size();
            
            ans.clear();
            euler(mp_str["JFK"]);
            reverse(ans.begin(),ans.end());
            return ans;
        }
    private:
        map<string,int> mp_str;
        map<int,string> mp_int;
        vector<string> edge[10010];
        vector<string> ans;
        int vis[1010][1010];
    };

    一些想法:

      1. 写好一题之后如果时间or空间复杂度的排名不咋地,要去看看别人的写法。

      2. 数据结构要灵活使用,别死脑筋的一直用之前的套路,想一想用哪些stl的工具可以提高效率。

  • 相关阅读:
    win10 访问远程文件夹 此共享需要过时的SMB1协议 你不能访问此共享文件夹
    Navicat 1142 SELECT command denied to user 'sx'@'xxx' for table 'user'
    MySQL 密码参数配置与修改 validate_password
    MySQL 命令行下更好的显示查询结果
    MySQL 数据库的存储结构
    MySQL实验 内连接优化order by+limit 以及添加索引再次改进
    MySQL实验 子查询优化双参数limit
    MySQL 索引结构 hash 有序数组
    MySQL 树形索引结构 B树 B+树
    hbase2.1.9 centos7 完全分布式 搭建随记
  • 原文地址:https://www.cnblogs.com/z1141000271/p/12628489.html
Copyright © 2020-2023  润新知