269. Alien Dictionary
这些就是有向图的边,对于有向图中的每个结点,计算其入度,然后从入度为0的结点开始 BFS 遍历这个有向图,然后将遍历路径保存下来返回即可。下面来看具体的做法:
根据之前讲解,需用 TreeSet 来保存这些 pair,我们还需要一个 HashSet 来保存所有出现过的字母,需要一个一维数组 in 来保存每个字母的入度,另外还要一个 queue 来辅助拓扑遍历,我们先遍历单词集,把所有字母先存入 HashSet,然后我们每两个相邻的单词比较,找出顺序 pair,然后我们根据这些 pair 来赋度,我们把 HashSet 中入度为0的字母都排入 queue 中,然后开始遍历,如果字母在 TreeSet 中存在,则将其 pair 中对应的字母的入度减1,若此时入度减为0了,则将对应的字母排入 queue 中并且加入结果 res 中,直到遍历完成。
最后看结果 sb 和 map.size() 中的元素个数是否相同,若不相同则说明可能有环存在,返回空字符串
Map<out, in>
class Solution { public String alienOrder(String[] words) { int[] indegree = new int[26]; Map<Character, Set<Character>> g = new HashMap<>(); buildGraph(g, words, indegree); return bfs(g, indegree); } private void buildGraph(Map<Character, Set<Character>> g, String[] words, int[] indegree){ for(String word : words){ for(char c : word.toCharArray()){ g.putIfAbsent(c, new HashSet<>()); } } 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); if(!g.get(out).contains(in)){ g.get(out).add(in); indegree[in - 'a']++; } break; } } } } private String bfs(Map<Character, Set<Character>> g, int[] indegree){ StringBuilder sb = new StringBuilder(); int totalChars = g.size(); Queue<Character> q = new LinkedList<>(); for(char c : g.keySet()){ if(indegree[c - 'a'] == 0){ sb.append(c); q.offer(c); } } while(!q.isEmpty()){ char out = q.poll(); if(g.get(out) == null || g.get(out).size() == 0) continue; for(char in : g.get(out)){ indegree[in - 'a']--; if(indegree[in - 'a'] == 0){ q.offer(in); sb.append(in); } } } return sb.length() == totalChars ? sb.toString() : ""; } }
269. Alien Dictionary