LeetCode 269 Alien Dictionary
方法:拓扑排序BFS
时间复杂度:O(mn),n代表words数组的长度,m代表words里面最长的单词的长度
空间复杂度:O(1),主要是题目说了只包括英文小写字母,那么不管是图的表示,还是Queue,都应该是在常数范围内
想法:根据给的东西构建字母的先后顺序,这个描述想到拓扑排序还是不难的。拓扑排序也是算法当中非常基础的内容,实现起来无非就是BFS外加一个记录入度的哈希表。这个题主要难点在于如何正确地构建这张图。构图的思路是用一个index扫描原数组,然后每次都跟它的后一个字符串进行比较,因为前一个字符串的字典序比后一个字符串更靠前,因此这俩直接比较出来那一个第一个不同的字符,就可以得到一对字符之间的字典序关系。比如说"wrt","wrf",我们有个指针找到第三位,那么显然t在f之前,t的child里面就可以放进去f。这个题还有个比较蛋疼的点,在于题目给的数据不一定是合法的,有可能根本构造不出来。所以要加入一行代码:
if (index == words[i + 1].length() && index < words[i].length()) { return null; }
你扫描完了这俩字符串,结果发现后面字符串是前面字符串的一个前缀,然后前面字符串比后面那个还长,比如说"abc"在"a"前面,这肯定是不合理。这种情况我们用return null解决,假如返回的图是null,我们会认为构图的时候出问题了,然后直接返回空字符串表明,根据这输入数据做不了。
代码:
class Solution {
public String alienOrder(String[] words) {
Map<Character, Set<Character>> graph = createGraph(words);
return topologySort(graph);
}
private String topologySort(Map<Character, Set<Character>> graph) {
if (graph == null) {
return "";
}
Map<Character, Integer> in = new HashMap<>();
for (Character key : graph.keySet()) {
if (!in.containsKey(key)) {
in.put(key, 0);
}
Set<Character> child = graph.get(key);
for (Character c : child) {
int tmp = in.getOrDefault(c, 0) + 1;
in.put(c, tmp);
}
}
Queue<Character> queue = new LinkedList<>();
int cnt = 0;
StringBuilder sb = new StringBuilder();
for (Character key : in.keySet()) {
if (in.get(key) == 0) {
queue.offer(key);
}
}
while (!queue.isEmpty()) {
Character head = queue.poll();
cnt++;
sb.append(head);
for (Character neighbor : graph.get(head)) {
int tmp = in.get(neighbor) - 1;
in.put(neighbor, tmp);
if (tmp == 0) {
queue.offer(neighbor);
}
}
}
return cnt == graph.size() ? sb.toString() : "";
}
private Map<Character, Set<Character>> createGraph(String[] words) {
Map<Character, Set<Character>> map = new HashMap<>();
for (int i = 0; i < words.length; i++) {
for (int j = 0; j < words[i].length(); j++) {
char c = words[i].charAt(j);
if (!map.containsKey(c)) {
map.put(c, new HashSet<Character>());
}
}
}
for (int i = 0; i < words.length - 1; i++) {
int index = 0;
while (index < words[i].length() && index < words[i + 1].length()) {
char cf = words[i].charAt(index);
char cl = words[i + 1].charAt(index);
if (cf != cl) {
map.get(cf).add(cl);
break;
}
index++;
}
if (index == words[i + 1].length() && index < words[i].length()) {
return null;
}
}
return map;
}
}