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
class Solution {
public boolean areSentencesSimilarTwo(String[] sentence1, String[] sentence2, List<List<String>> similarPairs) {
if (sentence1.length != sentence2.length) {
return false;
}
Map<String, Set<String>> wordsSimilarSet = new HashMap<>();
for (List<String> pair : similarPairs) {
wordsSimilarSet.putIfAbsent(pair.get(0), new HashSet<>());
wordsSimilarSet.get(pair.get(0)).add(pair.get(1));
wordsSimilarSet.putIfAbsent(pair.get(1), new HashSet<>());
wordsSimilarSet.get(pair.get(1)).add(pair.get(0));
}
for (int i = 0; i < sentence1.length; i++) {
if (sentence1[i].equals(sentence2[i])) {
continue;
}
if (!wordsSimilarSet.containsKey(sentence1[i]) || !wordsSimilarSet.containsKey(sentence2[i])) {
return false;
}
if (!dfs(wordsSimilarSet, sentence1[i], sentence2[i], new HashSet<>())) {
return false;
}
}
return true;
}

private boolean dfs(Map<String, Set<String>> wordsSimilarSet, String word1, String word2, Set<String> visited) {
if (wordsSimilarSet.get(word1).contains(word2)) {
return true;
}
for (String child : wordsSimilarSet.get(word1)) {
if (visited.add(child) && dfs(wordsSimilarSet, child, word2, visited)) {
return true;
}
}
return false;
}
}

每个word就是一个node, dfs即可.

时间复杂度: O(V(每个node都要判断是否包含word2) + E(因为for循环要把所有的child都add一遍)) V是pairs中unique words的个数, E是pairs这个list的size, 也就是edge的个数.
空间复杂度: O(V) 可能是链表.

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
65
66
67
68
69
class Solution {
private static class UnionFind {
private int[] parent;
private int[] rank;

private UnionFind(int size) {
parent = new int[size];
rank = new int[size];
for (int i = 0; i < parent.length; i++) {
parent[i] = i;
rank[i] = 1;
}
}

private int find(int x) {
if (x == parent[x]) {
return x;
}
return parent[x] = find(parent[x]);
}

private void union(int x, int y) {
int xRoot = find(x);
int yRoot = find(y);
if (xRoot != yRoot) {
if (rank[xRoot] > rank[yRoot]) {
parent[yRoot] = xRoot;
} else if (rank[xRoot] < rank[yRoot]) {
parent[xRoot] = yRoot;
} else {
parent[yRoot] = xRoot;
rank[xRoot] += 1;
}
}
}

private boolean isConnected(int x, int y) {
return find(x) == find(y);
}
}

public boolean areSentencesSimilarTwo(String[] sentence1, String[] sentence2, List<List<String>> similarPairs) {
if (sentence1.length != sentence2.length) {
return false;
}
Map<String, Integer> stringIdxMap = new HashMap<>();
int idx = 0;
UnionFind uf = new UnionFind(similarPairs.size() * 2);
for (List<String> pair : similarPairs) {
if (!stringIdxMap.containsKey(pair.get(0))) {
stringIdxMap.put(pair.get(0), idx++);
}
if (!stringIdxMap.containsKey(pair.get(1))) {
stringIdxMap.put(pair.get(1), idx++);
}
uf.union(stringIdxMap.get(pair.get(0)), stringIdxMap.get(pair.get(1)));
}
for (int i = 0; i < sentence1.length; i++) {
if (sentence1[i].equals(sentence2[i])) {
continue;
}
if (!stringIdxMap.containsKey(sentence1[i]) || !stringIdxMap.containsKey(sentence2[i])
|| !uf.isConnected(stringIdxMap.get(sentence1[i]), stringIdxMap.get(sentence2[i]))) {
return false;
}
}
return true;
}
}

Union Find(path compression + union by rank)

时间复杂度: O(N + P) N是sentence1的length因为我们要遍历. 每次遍历平均是O(1). P是pair的长度, 因为我们要往map中添加string以及UF中union string. 都是平均O(1).
空间负复杂度: O(P) UF需要parent和rank数组, 都是P的二倍, 是O(2P), map也是O(P). 加在一起是O(3P)也就是O(P).