- Alien Dictionary
There is a new alien language which uses the latin alphabet. However, the order among letters are unknown to you. You receive a list of non-empty words from the dictionary, where words are sorted lexicographically by the rules of this new language. Derive the order of letters in this language.
Example
Example 1:
Input:[“wrt”,“wrf”,“er”,“ett”,“rftt”]
Output:“wertf”
Explanation:
from “wrt"and"wrf” ,we can get ‘t’<‘f’
from “wrt"and"er” ,we can get ‘w’<‘e’
from “er"and"ett” ,we can get ‘r’<‘t’
from “ett"and"rftt” ,we can get ‘e’<‘r’
So return “wertf”
Example 2:
Input:[“z”,“x”]
Output:“zx”
Explanation:
from “z” and “x”,we can get ‘z’ < ‘x’
So return “zx”
Notice
You may assume all letters are in lowercase.
The dictionary is invalid, if a is prefix of b and b is appear before a.
If the order is invalid, return an empty string.
There may be multiple valid order of letters, return the smallest in normal lexicographical order
解法1:
topologial sorting.
注意:
- 要用priority queue,因为结果有顺序。而且要用minHeap!
- 建图时把word[i]和word[i+1]比较,从头开始比,碰到第一个不同的字符就返回。
class Solution {
public:
/**
* @param words: a list of words
* @return: a string which is correct order
*/
string alienOrder(vector<string> &words) {
map<char, set<char>> graph = buildGraph(words);
return topologicalSorting(graph);
}
private:
map<char, set<char>> buildGraph(vector<string> &words) {
map<char, set<char>> graph;
//put all the chars in graph, the set is empty at this time
for (int i = 0; i < words.size(); ++i) {
for (int j = 0; j < words[i].size(); ++j) {
if (graph.find(words[i][j]) == graph.end())
graph[words[i][j]] = {};
}
}
for (int i = 0; i < words.size() - 1; ++i) {
int len = min(words[i].size(), words[i + 1].size());
for (int j = 0; j < len; ++j) {
if (words[i][j] != words[i + 1][j]) {
graph[words[i][j]].insert(words[i + 1][j]);
break;
}
}
}
return graph;
}
map<char, int> getIndegree(map<char, set<char>> graph) {
map<char, int> indegree;
for (auto elem : graph) {
indegree[elem.first] = 0;
}
for (auto elem: graph) {
for (auto c : elem.second) {
indegree[c]++;
}
}
return indegree;
}
string topologicalSorting(map<char, set<char>> graph) {
map<char, int> indegree = getIndegree(graph);
priority_queue<char, vector<char>, greater<char>> pq; //minHeap
string str;
for (auto elem : indegree) {
if (indegree[elem.first] == 0) {
pq.push(elem.first);
}
}
while(!pq.empty()) {
char topChar = pq.top();
pq.pop();
str += topChar;
for (char neighbor : graph[topChar]) {
indegree[neighbor]--;
if (indegree[neighbor] == 0) {
pq.push(neighbor);
}
}
}
if (str.size() != indegree.size()) return "";
return str;
}
};
二刷:跟上面的方法类似。注意:
- 最后要检查res.size() == inDegrees.size()。这里是为了防止有环,有环的话只会输出环外的元素。当然有环的话也不能用topological sorting。
- inDegrees[l.second]++ 必须在i循环外进行,不然的话,同样的链接比如说(a,b)可能会出现多次,而b的indegree会每次都错误累加。但实际上只要加1次就可以了。
class Solution {
public:
string alienOrder(vector<string>& words) {
set<pair<char, char>> linkSets;
unordered_map<char, int> inDegrees;
priority_queue<char, vector<char>, greater<char>> minHeap;
string res;
//initialization
for (auto word : words) {
for (auto c : word) {
inDegrees[c] = 0;
}
}
//construct linkSets
int j = 0;
for (int i = 0; i < (int)words.size() - 1; i++) {
int minLen = min(words[i].size(), words[i + 1].size());
for (j = 0; j < minLen; j++) {
if (words[i][j] != words[i + 1][j]) {
linkSets.insert({words[i][j], words[i + 1][j]});
//inDegrees[words[i + 1][j]]++; //注意要放到循环外面,因为如果有两个同样的连接(a,b),这里会把b的indegree加到2,但实际上只有1.
break;
}
}
if (j == minLen && words[i].size() > words[i + 1].size()) return "";
}
for (auto l : linkSets) {
inDegrees[l.second]++;
}
//topological sorting
for (auto in : inDegrees) {
if (in.second == 0) {
minHeap.push(in.first);
}
}
while (!minHeap.empty()) {
char topChar = minHeap.top();
minHeap.pop();
res += topChar;
for (auto link : linkSets) {
if (topChar == link.first) {
inDegrees[link.second]--;
if (inDegrees[link.second] == 0) {
minHeap.push(link.second);
}
}
}
}
return res.size() == inDegrees.size() ? res : ""; //防止有环,有环的话只会输出环外的元素
}
};