Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit 2cbd9ce

Browse files
feat: add solutions to lc problem: No.0839 (doocs#3384)
No.0839.Similar String Groups
1 parent 2d7c1e4 commit 2cbd9ce

File tree

13 files changed

+704
-303
lines changed

13 files changed

+704
-303
lines changed

‎solution/0800-0899/0839.Similar String Groups/README.md‎

Lines changed: 227 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -62,153 +62,288 @@ tags:
6262

6363
<!-- solution:start -->
6464

65-
### 方法一
65+
### 方法一:并查集
66+
67+
我们可以枚举字符串列表中的任意两个字符串 $s$ 和 $t,ドル由于 $s$ 和 $t$ 是字母异位词,因此如果 $s$ 和 $t$ 的对应位置字符不同的数量不超过 2ドル,ドル那么 $s$ 和 $t$ 是相似的,我们就可以使用并查集将 $s$ 和 $t$ 合并,如果合并成功,那么相似字符串组的数量减少 1ドル$。
68+
69+
最终相似字符串组的数量就是并查集中连通分量的数量。
70+
71+
时间复杂度 $O(n^2 \times (m + \alpha(n))),ドル空间复杂度 $O(n)$。其中 $n$ 和 $m$ 分别是字符串列表的长度和字符串的长度,而 $\alpha(n)$ 是 Ackermann 函数的反函数,可以看成是一个很小的常数。
6672

6773
<!-- tabs:start -->
6874

6975
#### Python3
7076

7177
```python
78+
class UnionFind:
79+
def __init__(self, n):
80+
self.p = list(range(n))
81+
self.size = [1] * n
82+
83+
def find(self, x):
84+
if self.p[x] != x:
85+
self.p[x] = self.find(self.p[x])
86+
return self.p[x]
87+
88+
def union(self, a, b):
89+
pa, pb = self.find(a), self.find(b)
90+
if pa == pb:
91+
return False
92+
if self.size[pa] > self.size[pb]:
93+
self.p[pb] = pa
94+
self.size[pa] += self.size[pb]
95+
else:
96+
self.p[pa] = pb
97+
self.size[pb] += self.size[pa]
98+
return True
99+
100+
72101
class Solution:
73102
def numSimilarGroups(self, strs: List[str]) -> int:
74-
def find(x):
75-
if p[x] != x:
76-
p[x] = find(p[x])
77-
return p[x]
78-
79-
n, l = len(strs), len(strs[0])
80-
p = list(range(n))
81-
for i in range(n):
82-
for j in range(i + 1, n):
83-
if sum(strs[i][k] != strs[j][k] for k in range(l)) <= 2:
84-
p[find(i)] = find(j)
85-
return sum(i == find(i) for i in range(n))
103+
n, m = len(strs), len(strs[0])
104+
uf = UnionFind(n)
105+
for i, s in enumerate(strs):
106+
for j, t in enumerate(strs[:i]):
107+
if sum(s[k] != t[k] for k in range(m)) <= 2 and uf.union(i, j):
108+
n -= 1
109+
return n
86110
```
87111

88112
#### Java
89113

90114
```java
91-
class Solution {
92-
private int[] p;
115+
class UnionFind {
116+
private final int[] p;
117+
private final int[] size;
93118

94-
public int numSimilarGroups(String[] strs) {
95-
int n = strs.length;
119+
public UnionFind(int n) {
96120
p = new int[n];
121+
size = new int[n];
97122
for (int i = 0; i < n; ++i) {
98123
p[i] = i;
124+
size[i] = 1;
99125
}
100-
for (int i = 0; i < n; ++i) {
101-
for (int j = i + 1; j < n; ++j) {
102-
if (check(strs[i], strs[j])) {
103-
p[find(i)] = find(j);
104-
}
105-
}
106-
}
107-
int res = 0;
108-
for (int i = 0; i < n; ++i) {
109-
if (i == find(i)) {
110-
++res;
111-
}
126+
}
127+
128+
public int find(int x) {
129+
if (p[x] != x) {
130+
p[x] = find(p[x]);
112131
}
113-
return res;
132+
return p[x];
114133
}
115134

116-
private boolean check(String a, String b) {
117-
int cnt = 0;
118-
int n = a.length();
119-
for (int i = 0; i < n; ++i) {
120-
if (a.charAt(i) != b.charAt(i)) {
121-
++cnt;
122-
}
135+
public boolean union(int a, int b) {
136+
int pa = find(a), pb = find(b);
137+
if (pa == pb) {
138+
return false;
139+
}
140+
if (size[pa] > size[pb]) {
141+
p[pb] = pa;
142+
size[pa] += size[pb];
143+
} else {
144+
p[pa] = pb;
145+
size[pb] += size[pa];
123146
}
124-
return cnt <=2;
147+
return true;
125148
}
149+
}
126150

127-
private int find(int x) {
128-
if (p[x] != x) {
129-
p[x] = find(p[x]);
151+
class Solution {
152+
public int numSimilarGroups(String[] strs) {
153+
int n = strs.length, m = strs[0].length();
154+
UnionFind uf = new UnionFind(n);
155+
int cnt = n;
156+
for (int i = 0; i < n; ++i) {
157+
for (int j = 0; j < i; ++j) {
158+
int diff = 0;
159+
for (int k = 0; k < m; ++k) {
160+
if (strs[i].charAt(k) != strs[j].charAt(k)) {
161+
++diff;
162+
}
163+
}
164+
if (diff <= 2 && uf.union(i, j)) {
165+
--cnt;
166+
}
167+
}
130168
}
131-
return p[x];
169+
return cnt;
132170
}
133171
}
134172
```
135173

136174
#### C++
137175

138176
```cpp
139-
class Solution {
177+
class UnionFind {
140178
public:
141-
vector<int> p;
142-
143-
int numSimilarGroups(vector<string>& strs) {
144-
int n = strs.size();
145-
p.resize(n);
146-
for (int i = 0; i < n; ++i) p[i] = i;
147-
for (int i = 0; i < n; ++i)
148-
for (int j = i + 1; j < n; ++j)
149-
if (check(strs[i], strs[j]))
150-
p[find(i)] = find(j);
151-
int ans = 0;
152-
for (int i = 0; i < n; ++i)
153-
if (i == find(i))
154-
++ans;
155-
return ans;
179+
UnionFind(int n) {
180+
p = vector<int>(n);
181+
size = vector<int>(n, 1);
182+
iota(p.begin(), p.end(), 0);
156183
}
157184

158-
bool check(string a, string b) {
159-
int cnt = 0;
160-
for (int i = 0; i < a.size(); ++i)
161-
if (a[i] != b[i])
162-
++cnt;
163-
return cnt <= 2;
185+
bool unite(int a, int b) {
186+
int pa = find(a), pb = find(b);
187+
if (pa == pb) {
188+
return false;
189+
}
190+
if (size[pa] > size[pb]) {
191+
p[pb] = pa;
192+
size[pa] += size[pb];
193+
} else {
194+
p[pa] = pb;
195+
size[pb] += size[pa];
196+
}
197+
return true;
164198
}
165199

166200
int find(int x) {
167-
if (p[x] != x) p[x] = find(p[x]);
201+
if (p[x] != x) {
202+
p[x] = find(p[x]);
203+
}
168204
return p[x];
169205
}
206+
207+
private:
208+
vector<int> p, size;
209+
};
210+
211+
class Solution {
212+
public:
213+
int numSimilarGroups(vector<string>& strs) {
214+
int n = strs.size(), m = strs[0].size();
215+
int cnt = n;
216+
UnionFind uf(n);
217+
for (int i = 0; i < n; ++i) {
218+
for (int j = 0; j < i; ++j) {
219+
int diff = 0;
220+
for (int k = 0; k < m; ++k) {
221+
diff += strs[i][k] != strs[j][k];
222+
}
223+
if (diff <= 2 && uf.unite(i, j)) {
224+
--cnt;
225+
}
226+
}
227+
}
228+
return cnt;
229+
}
170230
};
171231
```
172232
173233
#### Go
174234
175235
```go
176-
func numSimilarGroups(strs []string) int {
177-
n := len(strs)
236+
type unionFind struct {
237+
p, size []int
238+
}
239+
240+
func newUnionFind(n int) *unionFind {
178241
p := make([]int, n)
242+
size := make([]int, n)
179243
for i := range p {
180244
p[i] = i
245+
size[i] = 1
181246
}
182-
check := func(a, b string) bool {
183-
cnt := 0
184-
for i := range a {
185-
if a[i] != b[i] {
186-
cnt++
187-
}
188-
}
189-
return cnt <= 2
247+
return &unionFind{p, size}
248+
}
249+
250+
func (uf *unionFind) find(x int) int {
251+
if uf.p[x] != x {
252+
uf.p[x] = uf.find(uf.p[x])
190253
}
191-
var find func(x int) int
192-
find = func(x int) int {
193-
if p[x] != x {
194-
p[x] = find(p[x])
195-
}
196-
return p[x]
254+
return uf.p[x]
255+
}
256+
257+
func (uf *unionFind) union(a, b int) bool {
258+
pa, pb := uf.find(a), uf.find(b)
259+
if pa == pb {
260+
return false
197261
}
198-
for i := 0; i < n; i++ {
199-
for j := i + 1; j < n; j++ {
200-
if check(strs[i], strs[j]) {
201-
p[find(i)] = find(j)
202-
}
203-
}
262+
if uf.size[pa] > uf.size[pb] {
263+
uf.p[pb] = pa
264+
uf.size[pa] += uf.size[pb]
265+
} else {
266+
uf.p[pa] = pb
267+
uf.size[pb] += uf.size[pa]
204268
}
205-
ans := 0
206-
for i := 0; i < n; i++ {
207-
if i == find(i) {
208-
ans++
269+
return true
270+
}
271+
272+
func numSimilarGroups(strs []string) int {
273+
n := len(strs)
274+
uf := newUnionFind(n)
275+
for i, s := range strs {
276+
for j, t := range strs[:i] {
277+
diff := 0
278+
for k := range s {
279+
if s[k] != t[k] {
280+
diff++
281+
}
282+
}
283+
if diff <= 2 && uf.union(i, j) {
284+
n--
285+
}
209286
}
210287
}
211-
return ans
288+
return n
289+
}
290+
```
291+
292+
#### TypeScript
293+
294+
```ts
295+
class UnionFind {
296+
private p: number[];
297+
private size: number[];
298+
299+
constructor(n: number) {
300+
this.p = Array.from({ length: n }, (_, i) => i);
301+
this.size = Array(n).fill(1);
302+
}
303+
304+
union(a: number, b: number): boolean {
305+
const pa = this.find(a);
306+
const pb = this.find(b);
307+
if (pa === pb) {
308+
return false;
309+
}
310+
if (this.size[pa] > this.size[pb]) {
311+
this.p[pb] = pa;
312+
this.size[pa] += this.size[pb];
313+
} else {
314+
this.p[pa] = pb;
315+
this.size[pb] += this.size[pa];
316+
}
317+
return true;
318+
}
319+
320+
find(x: number): number {
321+
if (this.p[x] !== x) {
322+
this.p[x] = this.find(this.p[x]);
323+
}
324+
return this.p[x];
325+
}
326+
}
327+
328+
function numSimilarGroups(strs: string[]): number {
329+
const n = strs.length;
330+
const m = strs[0].length;
331+
const uf = new UnionFind(n);
332+
let cnt = n;
333+
for (let i = 0; i < n; ++i) {
334+
for (let j = 0; j < i; ++j) {
335+
let diff = 0;
336+
for (let k = 0; k < m; ++k) {
337+
if (strs[i][k] !== strs[j][k]) {
338+
diff++;
339+
}
340+
}
341+
if (diff <= 2 && uf.union(i, j)) {
342+
cnt--;
343+
}
344+
}
345+
}
346+
return cnt;
212347
}
213348
```
214349

0 commit comments

Comments
(0)

AltStyle によって変換されたページ (->オリジナル) /