当前位置: 首页 > article >正文

BFS解决拓扑排序(3)_火星词典

个人主页:C++忠实粉丝
欢迎 点赞👍 收藏✨ 留言✉ 加关注💓本文由 C++忠实粉丝 原创

BFS解决拓扑排序(3)_火星词典

收录于专栏【经典算法练习】
本专栏旨在分享学习算法的一点学习笔记,欢迎大家在评论区交流讨论💌
    

目录

1. 题目链接

2. 题目描述

3. 解法

算法思路:

代码展示:

4, 算法总结 


1. 题目链接

OJ链接 : 火星词典

2. 题目描述

现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。

给定一个字符串列表 words ,作为这门语言的词典,words 中的字符串已经 按这门新语言的字母顺序进行了排序 。

请你根据该词典还原出此语言中已知的字母顺序,并 按字母递增顺序 排列。若不存在合法字母顺序,返回 "" 。若存在多种可能的合法字母顺序,返回其中 任意一种 顺序即可。

字符串 s 字典顺序小于 字符串 t 有两种情况:

  • 在第一个不同字母处,如果 s 中的字母在这门外星语言的字母顺序中位于 t 中字母之前,那么 s 的字典顺序小于 t 。
  • 如果前面 min(s.length, t.length) 字母都相同,那么 s.length < t.length 时,s 的字典顺序也小于 t 。

示例 1:

输入:words = ["wrt","wrf","er","ett","rftt"]
输出:"wertf"

示例 2:

输入:words = ["z","x"]
输出:"zx"

示例 3:

输入:words = ["z","x","z"]
输出:""
解释:不存在合法字母顺序,因此返回 "" 。

提示:

  • 1 <= words.length <= 100
  • 1 <= words[i].length <= 100
  • words[i] 仅由小写英文字母组成

3. 解法

算法思路:

将题意搞清楚之后, 这道题就变成了判断有向图时候有无环, 可以用拓扑排序解决.

如何搜集信息 (如何建图):

1. 两层for循环枚举出所有的两个字符串的组合;

2. 然后利用指针, 根据字典序规则找出信息

1. 建图:
使用邻接表 edges 来存储字母间的依赖关系,in 哈希表用来记录每个字母的入度。
首先遍历所有单词,初始化 in 表,确保每个字母都有一个初始值(入度为0)。

2. 确定字母顺序:
使用双重循环比较相邻的单词 words[i] 和 words[j],调用 add 函数来建立字母之间的顺序关系。
在 add 函数中:
找到第一个不同的字符,设定依赖关系(如 a->b 表示字母 a 在字母 b 之前)。
更新入度,并检查是否有非法情况(如一个单词是另一个单词的前缀而更长)。

3. 拓扑排序:
初始化一个队列,将所有入度为0的字母加入队列。
持续进行 BFS:
从队列中取出一个字母,添加到结果字符串 ret 中。
对于该字母的所有后续字母,减少它们的入度。如果某个字母的入度减为0,则将其加入队列。

4. 验证结果:
最后检查所有字母的入度,如果有字母的入度不为0,说明存在循环依赖关系,返回空字符串;否则,返回结果字符串。

代码展示:

class Solution {
    unordered_map<char, unordered_set<char>> edges;//邻接表来存储图
    unordered_map<char, int> in;//统计入度
    bool cheak;//处理遍历情况
public:
    string alienOrder(vector<string>& words) {
        //1. 建图 + 初始化入度哈希表
        for(auto s : words)
        {
            for(auto ch : s)
            {
                in[ch] = 0;
            }
        }
        int n = words.size();
        for(int i = 0; i < n; i++)
        {
            for(int j = i + 1; j < n; j++)
            {
                add(words[i], words[j]);
                if(cheak) return "";
            }
        }
        queue<char> q;
        string ret;
        for(auto [a, b] : in)
            if(b == 0) q.push(a);
        while(q.size())
        {
            char ch = q.front();
            q.pop();
            ret += ch;
            for(char c : edges[ch])
            {
                in[c]--;
                if(in[c] == 0) q.push(c);
            }
        }
        //判断
        for(auto [a, b] : in)
            if(b != 0) return "";
        return ret;
    }
    void add(string& s1, string& s2)
    {
        int n = min(s1.size(), s2.size());
        int i = 0;
        for(; i < n; i++)
        {
            if(s1[i] != s2[i])
            {
                char a = s1[i], b = s2[i]; //a -> b
                if(!edges.count(a) || !edges[a].count(b))
                {
                    edges[a].insert(b);
                    in[b]++;
                }
                break;
            }
        }
        if(i == s2.size() && i < s1.size()) cheak = true;
    }
};

 

4, 算法总结 

时间复杂度:O(N) + O(W),其中 N 是字母数量,W 是单词总长度。这是因为我们需要遍历所有单词和字母。

空间复杂度:O(N),用于存储字母的邻接表和入度。


http://www.kler.cn/a/373991.html

相关文章:

  • Excel重新踩坑4:快捷键;逻辑函数;文本函数;日期相关函数;查找与引用函数;统计类函数;数组公式
  • 【万户软件-注册安全分析报告-无验证方式导致安全隐患】
  • 对话瀚荃:为何欧美拟统一采用USB-C充电接口?
  • 记一次踩坑ConcurrentModificationException
  • MYSQL-SQL-03-DQL(Data Query Language,数据查询语言)(单表查询)
  • 推荐一款优秀的pdf编辑器:Ashampoo PDF Pro
  • 机器学习-期末考核-深度学习
  • 【jvm】如何设置新生代和老年代的比例
  • 【笔记】数据结构与算法
  • Golang | Leetcode Golang题解之第514题自由之路
  • pip使用
  • 2024年华为OD机试真题---字符串重新排序
  • PETG耗材3d打印技巧
  • 15分钟学 Go 第 21 天:标准库使用
  • Elasticsearch开源仓库404 7万多star一夜清零
  • 数据结构-选择排序笔记
  • PyTorch提供的多GPU数据并行nn.DataParallel
  • Docker Compose --- 管理多容器应用
  • centos7配置keepalive+lvs
  • X2JS: XML与JSON的完美转换工具
  • 基础IO -- 标准错误输出stderr
  • defer和async的区别
  • C#进阶1
  • vue3 ref和reactive踩坑
  • 实现Vue3/Nuxt3 预览excel文件
  • git revert‌和git reset,慎用git revert‌