## Sunday, May 20, 2018

### LeetCode 734 - Sentence Similarity

Given two sentences `words1, words2` (each represented as an array of strings), and a list of similar word pairs `pairs`, determine if two sentences are similar.
For example, “great acting skills” and “fine drama talent” are similar, if the similar word pairs are `pairs = [["great", "fine"], ["acting","drama"], ["skills","talent"]]`.
Note that the similarity relation is not transitive. For example, if “great” and “fine” are similar, and “fine” and “good” are similar, “great” and “good” are not necessarily similar.
However, similarity is symmetric. For example, “great” and “fine” being similar is the same as “fine” and “great” being similar.
Also, a word is always similar with itself. For example, the sentences `words1 = ["great"], words2 = ["great"], pairs = []` are similar, even though there are no specified similar word pairs.
Finally, sentences can only be similar if they have the same number of words. So a sentence like `words1 = ["great"]` can never be similar to `words2 = ["doubleplus","good"]`.
Note:
• The length of `words1` and `words2` will not exceed `1000`.
• The length of `pairs` will not exceed `2000`.
• The length of each `pairs[i]` will be `2`.
• The length of each `words[i]` and `pairs[i][j]` will be in the range `[1, 20]`.

Use hashtable to store mapping from word to its similar words.
public boolean areSentencesSimilar(String[] words1, String[] words2, String[][] pairs) {
if (words1.length != words2.length) return false;

Map<String, Set<String>> similar_words = new HashMap<>();

for (String[] pair : pairs) {
if (!similar_words.containsKey(pair[0]))
similar_words.put(pair[0], new HashSet<>());
if (!similar_words.containsKey(pair[1]))
similar_words.put(pair[1], new HashSet<>());
}

for (int i = 0; i < words1.length; ++i) {
if (words1[i].equals(words2[i])) continue;
if (!similar_words.containsKey(words1[i])) return false;
if (!similar_words.get(words1[i]).contains(words2[i])) return false;
}

return true;
}
First of all, we need to make sure we have considered of all the edge cases in this question. So there are 3 conditions for a word:
1. There is no similar pair exists for this word.
2. There is one pair exists for this word.
3. There are more than one pair exists for this word.
Considering about all the above conditions, we need to use a one to more relationship when storing the pair relationship. This can be realized via a `HashMap<String, HashSet<String>>` for quick (`O(1)`) search for a word's similar words.
And based on the question, we have two conditions when the two input arrays are not similar:
1. The two input array are of different length.
2. For a word at position `i` in `words[]`, if this word does not exists in the HashMap or the HashSet corresponding to it does not contains `words2[i]`. Meanwhile, `words1[i] != words2[i]`.
Time complexity: `O(n)` where `n` is the greater one among `words1.length` and `pairs.length`.
Space complexity: `O(2*m) = O(m)` where `m` is the length of `pairs`.
```    public boolean areSentencesSimilar(String[] words1, String[] words2, String[][] pairs) {
if (words1.length != words2.length) return false;
Map<String, Set<String>> map = new HashMap<>();
for (String[] pair : pairs) {
if (!map.containsKey(pair[0])) {
map.put(pair[0], new HashSet<>());
}
if (!map.containsKey(pair[1])) {
map.put(pair[1], new HashSet<>());
}
}

for (int i = 0; i < words1.length; i++) {
if (!words1[i].equals(words2[i]) && (!map.containsKey(words1[i]) || !map.get(words1[i]).contains(words2[i]))) {
return false;
}
// if (words1[i].equals(words2[i])) continue;
// if (map.containsKey(words1[i]) && map.get(words1[i]).contains(words2[i])) continue;
// return false;
}

return true;
}```