269 alien dict

269 Alien Dict

我们重点分析时间复杂度,我们假设拓扑图中有n个节点和m条边。下面我们首先分析下DFS的复杂度:DFS会遍历所有的节点和所有的边,因此复杂度很好分析那就是O(n + m),这是一个线性时间,比较好的算法。

BFS方式,首先需要init一个拥有n个节点的列表,并且需要遍历一遍图中的边逻辑;这个方式的时间复杂度也是O(n + m),同样是一个线性时间

Topo-bfs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
class  {
private Map<Character, Set<Character>> graph;
private Map<Character, Integer> inDegree;
private String[] words;
public String alienOrder(String[] words) {
if (words == null || words.length == 0) return "";
this.words = words;
StringBuilder sb = new StringBuilder();
buildGraph();
Queue<Character> queue = new LinkedList<>();
for (Character c : inDegree.keySet()) {
if (inDegree.get(c) == 0) {
queue.offer(c);
}
}

while (!queue.isEmpty()) {
char cur = queue.poll();
sb.append(cur);
for (char next : graph.getOrDefault(cur, new LinkedHashSet<>())) {
if (inDegree.get(next) == 1) {
queue.offer(next);
}
inDegree.put(next, inDegree.get(next) - 1);
}
}

if (inDegree.size() != sb.length()) {
return "";
}

return sb.toString();
}

public void buildGraph() {
graph = new HashMap<>();
inDegree = new HashMap<>();

for (String word : words) {
for (Character c : word.toCharArray()) {
inDegree.putIfAbsent(c, 0);
}
}

for (int i = 0; i < words.length - 1; i++) {
char[] arr1 = words[i].toCharArray();
char[] arr2 = words[i + 1].toCharArray();
int len = Math.min(arr1.length, arr2.length);
for (int j = 0; j < len; j++) {
char a = arr1[j];
char b = arr2[j];
if (a != b) {
graph.putIfAbsent(a, new LinkedHashSet<>());
if (!graph.get(a).contains(b)) {
graph.get(a).add(b);
inDegree.put(b, inDegree.get(b) + 1);
}
break;
//["wrt","wrf","er","ett","rftt","te"]
}
}
}
}
}

Topo-DFS:

建图基本和bfs法一样,唯一区别是需要一个visit map来知道三种状态:unseen,visiting和visited, 不需要indegree的map了

注意两点:

  1. visited的条件,也就是入结果的条件是这个char的邻居都被visited了
  2. 结果放入sb的顺序是和topological order反的,所以最后输出时候要reverse sb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
class  {
private Map<Character, Set<Character>> graph;
// -1 mean unseen, 0 means visiting, 1 means visited
private Map<Character, Integer> visit;
private String[] words;
public String alienOrder(String[] words) {
this.words = words;
visit = new HashMap<>();
graph = new HashMap<>();
if (words == null || words.length == 0) {
return "";
}
buildGraph();
StringBuilder sb = new StringBuilder();
for (char c : visit.keySet()) {
if (!dfs(c, sb)) return "";
}
System.out.println("reverse of res is: " + sb.toString());
return sb.reverse().toString();
}

private boolean dfs(char cur, StringBuilder sb) {
if (visit.get(cur) == 1) {//visited
return true;
}
if (visit.get(cur) == 0) {//have cycle
return false;
}
visit.put(cur, 0);
for (char next : graph.getOrDefault(cur, new HashSet<>())) {
if (!dfs(next, sb)) {
return false;
}
}
visit.put(cur, 1);
sb.append(cur);//小弟都被visited,自己就被visited
return true;
}

public void buildGraph() {
for (String word : words) {
for (char c : word.toCharArray()) {
visit.put(c, -1);
}
}
for (int i = 0; i < words.length - 1; i++) {
char[] arr1 = words[i].toCharArray();
char[] arr2 = words[i + 1].toCharArray();
int len = Math.min(arr1.length, arr2.length);
for (int j = 0; j < len; j++) {
char one = arr1[j];
char two = arr2[j];
graph.putIfAbsent(one, new HashSet<>());
if (one != two) {
graph.get(one).add(two);
break;
}
}
}
}
}
1
2
3
4
5
6

public static void main(String[] args) {
String[] input = {"ab", "bc", "cde"};
Solution sol = new Solution();
System.out.println("order is: " + sol.alienOrder(input));
}