Problems: https://leetcode.com/problems/alien-dictionary/
Solution:
Topological Sort
建立拓扑图并寻找所有字符的入度(buildGraph),再寻找入度为0的字符取出,邻接字符入度减一(bfs)
class Solution {
public String alienOrder(String[] words) {
Map<Character, Set<Character>> map = new HashMap<>();
int[] indegree = new int[26];
// 利用buildGraph记录邻接字符(map)和所有字符的入度(indegree)
buildGraph(indegree, map, words);
// 不断取出入度为1的字符并存到最后的结果中
return bfs(indegree, map);
}
public void buildGraph(int[] indegree, Map<Character, Set<Character>> map, String[] words) {
// words中存在的所有字符
for(String word : words) {
for(char ch : word.toCharArray()) {
map.putIfAbsent(ch, new HashSet<Character>());
}
}
// 寻找字符顺序
for(int i = 1; i < words.length; i++) {
String first = words[i-1];
String second = words[i];
int len = Math.min(first.length(), second.length());
for(int j = 0; j < len; j++) {
// 寻找第一个不同的字符
if(first.charAt(j) != second.charAt(j)) {
// 出度
char out = first.charAt(j);
// 入度
char in = second.charAt(j);
// 只有遇见还没有被记录过入度的字符时进行存储和入度记录
// 一是因为HashSet存入相同的值会报异常
// 二是因为入度只需要记录一次即可
if(!map.get(out).contains(in)) {
map.get(out).add(in);
indegree[in - 'a']++; // 用[in - 'a']可以将字母存入对应index的位置
}
// 一对单词中,一旦出现一个字符不同,之后字符的顺序都失去意义
// 所以直接break
break;
}
}
}
}
public String bfs(int[] indegree, Map<Character, Set<Character>> map) {
StringBuilder sb = new StringBuilder();
Queue<Character> q = new LinkedList<>();
// 只需要存已经在keySet中的字符,不需要遍历所有26个字母
// 如果入度为0,存入queue
for(char ch : map.keySet()) {
if(indegree[ch - 'a'] == 0) {
q.offer(ch);
}
}
while(!q.isEmpty()) {
// 将入度为0的字符存入结果sb中
char out = q.poll();
sb.append(out);
// 拓扑(queue)中已经取出(poll)的node,其邻接node的入度-1
for(char in : map.get(out)) {
indegree[in - 'a']--;
// 寻找入度为0的字母存入queue
if(indegree[in - 'a'] == 0) {
q.offer(in);
}
}
}
// 检查sb的长度,如果和words中的字母个数相同说明order是valid,否则的话order中要么存在多余的字母,要么就是少字母
return sb.length() == map.size() ? sb.toString() : "";
}
}
Reference: https://www.youtube.com/watch?v=RIrTuf4DfPE
Comments: 这题理解到血压升高,还是太垃圾了