【题解】LeetCode LCR 114. 火星词典
【题解】LeetCode LCR 114. 火星词典
- 火星词典题目链接
- 题目描述
- 样例
- 数据范围
- 题意分析
- 思路
- AC代码
火星词典题目链接
题目描述
- 题目标签:
广度优先遍历,深度优先遍历,图,拓扑排序 - 题目分类:
hard
现有一种使用英语字母的外星文语言,这门语言的字母顺序与英语顺序不同。
给定一个字符串列表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]仅由小写英文字母组成
题意分析
- 首先我们来理解一下题目是什么意思:题目要求我们根据
words返回一个字符串,words是一个存储了string的vector,words已经按照外星文的语言顺序排好序了,我们需要按照words中的信息,返回符合外星文语言顺序的递增的一个字符串,如果有多个符合要求的,返回其中一个即可 - 这样说你可能不太明白,接下来我结合样例解释一下,以样例一来解释
输入:
words=["wrt","wrf","er","ett","rftt"]
输出:"wertf"
- 返回非空字符串解释 :第一个字符串时
"wtf",按照题目里对字典序的描述,可以得出这里的字典三个字符的关系是递增的,注意不是依次递增,他们中间可能还有其他的字符,第二个字符串是"wrf",对比第一个字符可得,t是排在f前面的,换句话说,就是t的字典序小于f,以此类推
- 样例三返回空字符串
输入:
words=["z","x","z"]
输出:""
解释:不存在合法字母顺序,因此返回""。
- 先前我们解释了字典序的判定规则,这里就不赘述了,按照这个
words的内容可以得到z->x->z这个字典序关系,但是这不合理,z不可能既在x前面又在x后面,这是一个不合法的字符串,所以返回一个空字符串- 还有一个情况
words= ["abc","ab"],按理来说不该出现这种样例,我们理解来看前者的字典序是比后者大的,但是按照前面给的样例来看前者的字典序是小于后者的,c的字典序不可能比空值大,这是一个不合法的字符串,应该返回"",写的时候要注意一下
思路
- 刚开始毫无头绪,看了一下大佬的题解提到了
拓扑排序,看的一脸懵,不知道为啥能和拓扑排序扯上关系,看了解释以后,恍然大悟。每个字符都会存在比它字典序小/大的字符(第一个和最后一个字符除外),我们就可以它看作是一个有向图的边和顶点,在数据合法的情况下,一定可以构建一个合法的有向无环图,那么我们依次对这个图的入度为0的点进行遍历,这不就能都得到一个正确的序列了吗? - 解题步骤:
- 先把字符串
words中的点与点的对应关系建立起来,这就是建图- 接下来我们考虑 怎么高效查找, 构建一个有向无环图,图由边和顶点构成,我们需要存储当前顶点和它的指向的顶点,哈希表可以解决这个问题,因为只有26个字符,所以可能会存在大量相同的
key-value键值对,我们需要保证再出现这种情况时拒绝插入,我们就要先找到value是否存在于哈希表中,这种查找可能会出现很多次,所以查找必须高效,还有一个顶点可能有多条边,综合来看我们可以使用unordered_set来存value,既保证了查找的高效,也能存储点与点之间的关系- 存储每个顶点和他的入度信息,保持风格统一,这个我们也使用哈希表,不过记得要初始化,把
words中出现的字符和入度信息都添加进去,入度默认初始化为0- 根据我们前面的准备进行图的构建,比较相邻字符串的不同字符,得到他们之间的字典序关系,然后把他们添加到存储图的哈希表中
- 把所有入度为0的节点都添加到一个队列中
- 进行一次BFS
- 拓扑排序是可以检测有向图中是否存在环的,前面解释的样例3就是一个环,可以通过判断构建的字符串和存储顶点信息的哈希表的长度是否一致来判断是否存在环,就可以得出
words中的数据是否是合法的,从而决定我们最后返回什么值
AC代码
class Solution
{
public:string alienOrder(vector<string>& words) {std::unordered_map<char, std::unordered_set<char>> dict;std::unordered_map<char, int> in;for (std::string &word : words){for (char &ch : word){if (in.find(ch) == in.end())in[ch] = 0;}}// 信息搜集完了for (int i = 0; i < words.size() - 1; i++){int start = 0;std::string s1 = words[i];std::string s2 = words[i + 1];int len1 = s1.length();int len2 = s2.length();if (len1 > len2 && s1.find(s2, 0) == 0)return "";int minlen = std::min(len1, len2);while (start < minlen){char ch1 = s1[start], ch2 = s2[start];if (ch1 != ch2){if (dict[ch1].find(ch2) == dict[ch1].end()){dict[ch1].insert(ch2);in[ch2]++;}break;}start++;}// // 如果其中一个走完了还是没找到不相等的,如果前面的更长,就返回""// // 不可能出现"ab","abc"这种情况// if (start == minlen && words[i].length()>words[i+1].length())// return "";}std::queue<char> q;for (auto &it : in)if (it.second == 0) q.emplace(it.first);std::string ret = "";while (!q.empty()){char x = q.front();// key指向的所有数据q.pop();ret += x;if (dict.count(x)){for (char v : dict[x]){in[v]--;if (in[v] == 0)q.emplace(v);}}}if (ret.length() != in.size()) return "";return ret;}
};
这篇文章就到这里了,如果觉得写的还不错的话,欢迎点赞加关注,如果有写的不对的地方,欢迎批评指正( •̀ ω •́ )✧
