Skip to content

Commit 1c2ea29

Browse files
committed
0737-sentence-similarity-ii
1 parent 11e55c3 commit 1c2ea29

File tree

3 files changed

+112
-0
lines changed

3 files changed

+112
-0
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
/// 737. Sentence Similarity II
2+
/// Given two sentences words1, words2 (each represented as an array of strings), and a list of
3+
/// similar word pairs pairs, determine if two sentences are similar.
4+
///
5+
/// For example, words1 = ["great", "acting", "skills"] and words2 = ["fine", "drama", "talent"] are
6+
/// similar, if the similar word pairs are pairs = [["great", "good"], ["fine", "good"],
7+
/// ["acting","drama"], ["skills","talent"]].
8+
/// Note that the similarity relation is transitive. For example, if "great" and "good" are similar,
9+
/// and "fine" and "good" are similar, then "great" and "fine" are similar. Similarity is also
10+
/// symmetric. For example, "great" and "fine" being similar is the same as "fine" and "great" being
11+
/// similar.
12+
/// Also, a word is always similar with itself. For example, the sentences words1 = ["great"],
13+
/// words2 = ["great"], pairs = [] are similar, even though there are no specified similar word
14+
/// pairs.
15+
/// Finally, sentences can only be similar if they have the same number of words. So a sentence like
16+
/// words1 = ["great"] can never be similar to words2 = ["doubleplus","good"].
17+
18+
import XCTest
19+
20+
struct UnionFind<T: Hashable> {
21+
private var index: [T: Int] = [:]
22+
private var parent: [Int] = []
23+
private var size: [Int] = []
24+
25+
mutating func addSetWith(_ element: T) {
26+
index[element] = parent.count
27+
parent.append(parent.count)
28+
size.append(1)
29+
}
30+
31+
/// Path Compression.
32+
private mutating func setByIndex(_ index: Int) -> Int {
33+
if index != parent[index] {
34+
parent[index] = setByIndex(parent[index])
35+
}
36+
return parent[index]
37+
}
38+
39+
mutating func setOf(_ element: T) -> Int? {
40+
if let indexOfElement = index[element] {
41+
return setByIndex(indexOfElement)
42+
} else {
43+
return nil
44+
}
45+
}
46+
47+
mutating func unionSetsContaining(_ firstElement: T, and secondElement: T) {
48+
if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) {
49+
if firstSet != secondSet {
50+
if size[firstSet] < size[secondSet] {
51+
parent[firstSet] = secondSet
52+
size[secondSet] += size[firstSet]
53+
} else {
54+
parent[secondSet] = firstSet
55+
size[firstSet] += size[secondSet]
56+
}
57+
}
58+
}
59+
}
60+
61+
mutating func inSameSet(_ firstElement: T, and secondElement: T) -> Bool {
62+
if let firstSet = setOf(firstElement), let secondSet = setOf(secondElement) {
63+
return firstSet == secondSet
64+
} else {
65+
return false
66+
}
67+
}
68+
}
69+
70+
/// Approach: Union Find
71+
func areSentencesSimilarTwo(_ words1: [String], _ words2: [String], _ pairs: [[String]]) -> Bool {
72+
guard words1.count == words2.count else { return false }
73+
var dset = UnionFind<String>()
74+
for p in pairs {
75+
let word1 = p[0]
76+
let word2 = p[1]
77+
if dset.setOf(word1) == nil {
78+
dset.addSetWith(word1)
79+
}
80+
if dset.setOf(word2) == nil {
81+
dset.addSetWith(word2)
82+
}
83+
dset.unionSetsContaining(word1, and: word2)
84+
}
85+
for i in 0..<words1.count {
86+
if !dset.inSameSet(words1[i], and: words2[i]) {
87+
return false
88+
}
89+
}
90+
return true
91+
}
92+
93+
class Tests: XCTestCase {
94+
func testExample() {
95+
let words1 = ["great", "acting", "skills"]
96+
let words2 = ["fine", "drama", "talent"]
97+
let pairs = [
98+
["great", "good"],
99+
["fine", "good"],
100+
["drama", "acting"],
101+
["skills", "talent"],
102+
]
103+
XCTAssertTrue(areSentencesSimilarTwo(words1, words2, pairs))
104+
}
105+
}
106+
107+
Tests.defaultTestSuite.run()
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<playground version='5.0' target-platform='macos' executeOnSourceChanges='false'>
3+
<timeline fileName='timeline.xctimeline'/>
4+
</playground>

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,7 @@ You can visit the pages below to search problems by company tags. Then come back
6464
681 | [Next Closest Time](https://leetcode.com/problems/next-closest-time/description/) | [Solution](https://github.com/zhubofei/LeetCode-Swift/blob/master/0681-next-closest-time.playground/Contents.swift) | Simulation
6565
683 | [K Empty Slots](https://leetcode.com/problems/k-empty-slots/description/) | [Solution](https://github.com/zhubofei/LeetCode-Swift/blob/master/0683-k-empty-slots.playground/Contents.swift) | Sliding Window
6666
686 | [Repeated String Match](https://leetcode.com/problems/repeated-string-match/description/) | [Solution](https://github.com/zhubofei/LeetCode-Swift/blob/master/0686-repeated-string-match.playground/Contents.swift) | String
67+
737 | [Sentence Similarity II \*](https://leetcode.com/problems/sentence-similarity-ii/description/) | [Solution](https://github.com/zhubofei/LeetCode-Swift/blob/master/0737-sentence-similarity-ii.playground/Contents.swift) | Union Find
6768
843 | [Guess the Word \*](https://leetcode.com/problems/guess-the-word/description/) | [Solution](https://github.com/zhubofei/LeetCode-Swift/blob/master/0843-guess-the-word.playground/Contents.swift) | Minimax
6869

6970
**\* problems are not compilable on LeetCode. I have filed bug report for these problems.**

0 commit comments

Comments
 (0)