269 Alien Dictionary 火星詞典
Description:
There is a new alien language that uses the English alphabet. However, the order among the letters is unknown to you.
You are given a list of strings words from the alien language's dictionary, where the strings in words are sorted lexicographically by the rules of this new language.
Return a string of the unique letters in the new alien language sorted in lexicographically increasing order by the new language's rules. If there is no solution, return "". If there are multiple solutions, return any of them.
A string s is lexicographically smaller than a string t if at the first letter where they differ, the letter in s comes before the letter in t in the alien language. If the first min(s.length, t.length) letters are the same, then s is smaller if and only if s.length < t.length.
Example:
Example 1:
Input: words = ["wrt","wrf","er","ett","rftt"]
Output: "wertf"
Example 2:
Input: words = ["z","x"]
Output: "zx"
Example 3:
Input: words = ["z","x","z"]
Output: ""
Explanation: The order is invalid, so return "".
Constraints:
1 <= words.length <= 100
1 <= words[i].length <= 100
words[i] consists of only lowercase English letters.
題目描述:
現有一種使用英語字母的火星語言,這門語言的字母順序與英語順序不同。
給你一個字符串列表 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 建立圖, 記錄下各個結點的后繼結點
注意這里如果出現 "abc", "ab" 前后出現直接返回 ""
然后統計結點的入度
最后使用 BFS 拓撲排序得到字母的順序
時間復雜度為 O(mn), 空間復雜度為 O(n), n 為 words 數組長度, m 為 words 中字符串的平均長度
代碼:
C++:
class Solution
{
public:
string alienOrder(vector<string>& words)
{
map<char, unordered_set<char>> m;
int n = words.size(), count = 0;
vector<int> degree(26, -1);
string result = "";
for (int i = 0; i < n - 1; i++)
{
for (int j = 0; j < min(words[i].size(), words[i + 1].size()); j++)
{
if (words[i][j] != words[i + 1][j]) {
m[words[i][j]].insert(words[i + 1][j]);
break;
} else if (j == min(words[i].size(), words[i + 1].size()) - 1 and words[i].size() > words[i + 1].size()) return result;
}
}
for (const auto& word : words) for (const auto& c : word) degree[c - 'a'] = 0;
for (const auto& [key, value] : m) for (const auto& v : m[key]) ++degree[v - 'a'];
queue<char> q;
for (int i = 0; i < 26; i++)
{
if (!degree[i]) q.push((char)(i + 'a'));
if (degree[i] != -1) ++count;
}
while (!q.empty())
{
auto u = q.front();
q.pop();
result += u;
if (m.count(u))
{
for (const auto& v : m[u])
{
--degree[v - 'a'];
if (!degree[v - 'a']) q.push(v);
}
}
}
return result.size() == count ? result : "";
}
};
Java:
class Solution {
public String alienOrder(String[] words) {
Map<Character, Set<Character>> map = new HashMap<>();
int n = words.length, degree[] = new int[26], count = 0;
Arrays.fill(degree, -1);
for (int i = 0; i < n - 1; i++) {
for (int j = 0; j < Math.min(words[i].length(), words[i + 1].length()); j++) {
if (words[i].charAt(j) != words[i + 1].charAt(j)) {
Set<Character> set = map.getOrDefault(words[i].charAt(j), new HashSet<>());
set.add(words[i + 1].charAt(j));
map.putIfAbsent(words[i].charAt(j), set);
break;
} else if (j == Math.min(words[i].length(), words[i + 1].length()) - 1 && words[i].length() > words[i + 1].length()) return "";
}
}
for (String word : words) for (char c : word.toCharArray()) degree[c - 'a'] = 0;
for (Character key : map.keySet()) for (Character v : map.get(key)) ++degree[v - 'a'];
StringBuilder sb = new StringBuilder();
Queue<Character> queue = new LinkedList<>();
for (int i = 0; i < 26; i++) {
if (degree[i] == 0) queue.add((char)(i + 'a'));
if (degree[i] != -1) ++count;
}
while (!queue.isEmpty()) {
Character u = queue.poll();
sb.append(u);
if (map.containsKey(u)) {
for (Character v : map.get(u)) {
--degree[v - 'a'];
if (degree[v - 'a'] == 0) queue.add(v);
}
}
}
return sb.length() == count ? sb.toString() : "";
}
}
Python:
class Solution:
def alienOrder(self, words: List[str]) -> str:
graph, n, result, degree = defaultdict(set), len(words), '', [-1] * 26
for i in range(n - 1):
for j in range(min(len(words[i]), len(words[i + 1]))):
if words[i][j] != words[i + 1][j]:
graph[words[i][j]].add(words[i + 1][j])
break
elif j == min(len(words[i]), len(words[i + 1])) - 1 and len(words[i]) > len(words[i + 1]):
return result
for word in words:
for c in word:
degree[ord(c) - ord('a')] = 0
for key, value in graph.items():
for v in graph[key]:
degree[ord(v) - ord('a')] += 1
q, count = deque([chr(i + ord('a')) for i in range(26) if not degree[i]]), sum(degree[i] != -1 for i in range(26))
while q:
u = q.popleft()
result += u
for v in graph[u]:
degree[ord(v) - ord('a')] -= 1
if not degree[ord(v) - ord('a')]:
q.append(v)
return result if len(result) == count else ""