From 6c2eaede6346eed155d28e1bf5708797c9b98f6d Mon Sep 17 00:00:00 2001 From: yanglbme Date: Fri, 9 Aug 2024 08:56:22 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.0839 No.0839.Similar String Groups --- .../0839.Similar String Groups/README.md | 319 +++++++++++++----- .../0839.Similar String Groups/README_EN.md | 319 +++++++++++++----- .../0839.Similar String Groups/Solution.cpp | 70 ++-- .../0839.Similar String Groups/Solution.go | 73 ++-- .../0839.Similar String Groups/Solution.java | 74 ++-- .../0839.Similar String Groups/Solution.py | 42 ++- .../0839.Similar String Groups/Solution.ts | 53 +++ .../0840.Magic Squares In Grid/README.md | 6 +- .../0840.Magic Squares In Grid/README_EN.md | 12 +- .../0840.Magic Squares In Grid/Solution.ts | 6 +- .../README.md | 11 +- .../README_EN.md | 11 +- .../Solution.py | 11 +- 13 files changed, 704 insertions(+), 303 deletions(-) create mode 100644 solution/0800-0899/0839.Similar String Groups/Solution.ts diff --git a/solution/0800-0899/0839.Similar String Groups/README.md b/solution/0800-0899/0839.Similar String Groups/README.md index 5241ffdb57e6b..04de423deb653 100644 --- a/solution/0800-0899/0839.Similar String Groups/README.md +++ b/solution/0800-0899/0839.Similar String Groups/README.md @@ -62,73 +62,111 @@ tags: -### 方法一 +### 方法一:并查集 + +我们可以枚举字符串列表中的任意两个字符串 $s$ 和 $t$,由于 $s$ 和 $t$ 是字母异位词,因此如果 $s$ 和 $t$ 的对应位置字符不同的数量不超过 $2$,那么 $s$ 和 $t$ 是相似的,我们就可以使用并查集将 $s$ 和 $t$ 合并,如果合并成功,那么相似字符串组的数量减少 $1$。 + +最终相似字符串组的数量就是并查集中连通分量的数量。 + +时间复杂度 $O(n^2 \times (m + \alpha(n)))$,空间复杂度 $O(n)$。其中 $n$ 和 $m$ 分别是字符串列表的长度和字符串的长度,而 $\alpha(n)$ 是 Ackermann 函数的反函数,可以看成是一个很小的常数。 #### Python3 ```python +class UnionFind: + def __init__(self, n): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a, b): + pa, pb = self.find(a), self.find(b) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + class Solution: def numSimilarGroups(self, strs: List[str]) -> int: - def find(x): - if p[x] != x: - p[x] = find(p[x]) - return p[x] - - n, l = len(strs), len(strs[0]) - p = list(range(n)) - for i in range(n): - for j in range(i + 1, n): - if sum(strs[i][k] != strs[j][k] for k in range(l)) <= 2: - p[find(i)] = find(j) - return sum(i == find(i) for i in range(n)) + n, m = len(strs), len(strs[0]) + uf = UnionFind(n) + for i, s in enumerate(strs): + for j, t in enumerate(strs[:i]): + if sum(s[k] != t[k] for k in range(m)) <= 2 and uf.union(i, j): + n -= 1 + return n ``` #### Java ```java -class Solution { - private int[] p; +class UnionFind { + private final int[] p; + private final int[] size; - public int numSimilarGroups(String[] strs) { - int n = strs.length; + public UnionFind(int n) { p = new int[n]; + size = new int[n]; for (int i = 0; i < n; ++i) { p[i] = i; + size[i] = 1; } - for (int i = 0; i < n; ++i) { - for (int j = i + 1; j < n; ++j) { - if (check(strs[i], strs[j])) { - p[find(i)] = find(j); - } - } - } - int res = 0; - for (int i = 0; i < n; ++i) { - if (i == find(i)) { - ++res; - } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); } - return res; + return p[x]; } - private boolean check(String a, String b) { - int cnt = 0; - int n = a.length(); - for (int i = 0; i < n; ++i) { - if (a.charAt(i) != b.charAt(i)) { - ++cnt; - } + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; } - return cnt <= 2; + return true; } +} - private int find(int x) { - if (p[x] != x) { - p[x] = find(p[x]); +class Solution { + public int numSimilarGroups(String[] strs) { + int n = strs.length, m = strs[0].length(); + UnionFind uf = new UnionFind(n); + int cnt = n; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + int diff = 0; + for (int k = 0; k < m; ++k) { + if (strs[i].charAt(k) != strs[j].charAt(k)) { + ++diff; + } + } + if (diff <= 2 && uf.union(i, j)) { + --cnt; + } + } } - return p[x]; + return cnt; } } ``` @@ -136,79 +174,176 @@ class Solution { #### C++ ```cpp -class Solution { +class UnionFind { public: - vector p; - - int numSimilarGroups(vector& strs) { - int n = strs.size(); - p.resize(n); - for (int i = 0; i < n; ++i) p[i] = i; - for (int i = 0; i < n; ++i) - for (int j = i + 1; j < n; ++j) - if (check(strs[i], strs[j])) - p[find(i)] = find(j); - int ans = 0; - for (int i = 0; i < n; ++i) - if (i == find(i)) - ++ans; - return ans; + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); } - bool check(string a, string b) { - int cnt = 0; - for (int i = 0; i < a.size(); ++i) - if (a[i] != b[i]) - ++cnt; - return cnt <= 2; + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; } int find(int x) { - if (p[x] != x) p[x] = find(p[x]); + if (p[x] != x) { + p[x] = find(p[x]); + } return p[x]; } + +private: + vector p, size; +}; + +class Solution { +public: + int numSimilarGroups(vector& strs) { + int n = strs.size(), m = strs[0].size(); + int cnt = n; + UnionFind uf(n); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + int diff = 0; + for (int k = 0; k < m; ++k) { + diff += strs[i][k] != strs[j][k]; + } + if (diff <= 2 && uf.unite(i, j)) { + --cnt; + } + } + } + return cnt; + } }; ``` #### Go ```go -func numSimilarGroups(strs []string) int { - n := len(strs) +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { p := make([]int, n) + size := make([]int, n) for i := range p { p[i] = i + size[i] = 1 } - check := func(a, b string) bool { - cnt := 0 - for i := range a { - if a[i] != b[i] { - cnt++ - } - } - return cnt <= 2 + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) - } - return p[x] + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false } - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - if check(strs[i], strs[j]) { - p[find(i)] = find(j) - } - } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] } - ans := 0 - for i := 0; i < n; i++ { - if i == find(i) { - ans++ + return true +} + +func numSimilarGroups(strs []string) int { + n := len(strs) + uf := newUnionFind(n) + for i, s := range strs { + for j, t := range strs[:i] { + diff := 0 + for k := range s { + if s[k] != t[k] { + diff++ + } + } + if diff <= 2 && uf.union(i, j) { + n-- + } } } - return ans + return n +} +``` + +#### TypeScript + +```ts +class UnionFind { + private p: number[]; + private size: number[]; + + constructor(n: number) { + this.p = Array.from({ length: n }, (_, i) => i); + this.size = Array(n).fill(1); + } + + union(a: number, b: number): boolean { + const pa = this.find(a); + const pb = this.find(b); + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } +} + +function numSimilarGroups(strs: string[]): number { + const n = strs.length; + const m = strs[0].length; + const uf = new UnionFind(n); + let cnt = n; + for (let i = 0; i < n; ++i) { + for (let j = 0; j < i; ++j) { + let diff = 0; + for (let k = 0; k < m; ++k) { + if (strs[i][k] !== strs[j][k]) { + diff++; + } + } + if (diff <= 2 && uf.union(i, j)) { + cnt--; + } + } + } + return cnt; } ``` diff --git a/solution/0800-0899/0839.Similar String Groups/README_EN.md b/solution/0800-0899/0839.Similar String Groups/README_EN.md index 2efdadf25323c..05324e77ccdc2 100644 --- a/solution/0800-0899/0839.Similar String Groups/README_EN.md +++ b/solution/0800-0899/0839.Similar String Groups/README_EN.md @@ -60,73 +60,111 @@ tags: -### Solution 1 +### Solution 1: Union-Find + +We can enumerate any two strings $s$ and $t$ in the list of strings. Since $s$ and $t$ are anagrams, if the number of differing characters at corresponding positions between $s$ and $t$ does not exceed $2$, then $s$ and $t$ are similar. We can use the union-find data structure to merge $s$ and $t$. If the merge is successful, the number of similar string groups decreases by $1$. + +The final number of similar string groups is the number of connected components in the union-find structure. + +Time complexity is $O(n^2 \times (m + \alpha(n)))$, and space complexity is $O(n)$. Here, $n$ and $m$ are the length of the list of strings and the length of the strings, respectively, and $\alpha(n)$ is the inverse Ackermann function, which can be considered a very small constant. #### Python3 ```python +class UnionFind: + def __init__(self, n): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a, b): + pa, pb = self.find(a), self.find(b) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + class Solution: def numSimilarGroups(self, strs: List[str]) -> int: - def find(x): - if p[x] != x: - p[x] = find(p[x]) - return p[x] - - n, l = len(strs), len(strs[0]) - p = list(range(n)) - for i in range(n): - for j in range(i + 1, n): - if sum(strs[i][k] != strs[j][k] for k in range(l)) <= 2: - p[find(i)] = find(j) - return sum(i == find(i) for i in range(n)) + n, m = len(strs), len(strs[0]) + uf = UnionFind(n) + for i, s in enumerate(strs): + for j, t in enumerate(strs[:i]): + if sum(s[k] != t[k] for k in range(m)) <= 2 and uf.union(i, j): + n -= 1 + return n ``` #### Java ```java -class Solution { - private int[] p; +class UnionFind { + private final int[] p; + private final int[] size; - public int numSimilarGroups(String[] strs) { - int n = strs.length; + public UnionFind(int n) { p = new int[n]; + size = new int[n]; for (int i = 0; i < n; ++i) { p[i] = i; + size[i] = 1; } - for (int i = 0; i < n; ++i) { - for (int j = i + 1; j < n; ++j) { - if (check(strs[i], strs[j])) { - p[find(i)] = find(j); - } - } - } - int res = 0; - for (int i = 0; i < n; ++i) { - if (i == find(i)) { - ++res; - } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); } - return res; + return p[x]; } - private boolean check(String a, String b) { - int cnt = 0; - int n = a.length(); - for (int i = 0; i < n; ++i) { - if (a.charAt(i) != b.charAt(i)) { - ++cnt; - } + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; } - return cnt <= 2; + return true; } +} - private int find(int x) { - if (p[x] != x) { - p[x] = find(p[x]); +class Solution { + public int numSimilarGroups(String[] strs) { + int n = strs.length, m = strs[0].length(); + UnionFind uf = new UnionFind(n); + int cnt = n; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + int diff = 0; + for (int k = 0; k < m; ++k) { + if (strs[i].charAt(k) != strs[j].charAt(k)) { + ++diff; + } + } + if (diff <= 2 && uf.union(i, j)) { + --cnt; + } + } } - return p[x]; + return cnt; } } ``` @@ -134,79 +172,176 @@ class Solution { #### C++ ```cpp -class Solution { +class UnionFind { public: - vector p; - - int numSimilarGroups(vector& strs) { - int n = strs.size(); - p.resize(n); - for (int i = 0; i < n; ++i) p[i] = i; - for (int i = 0; i < n; ++i) - for (int j = i + 1; j < n; ++j) - if (check(strs[i], strs[j])) - p[find(i)] = find(j); - int ans = 0; - for (int i = 0; i < n; ++i) - if (i == find(i)) - ++ans; - return ans; + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); } - bool check(string a, string b) { - int cnt = 0; - for (int i = 0; i < a.size(); ++i) - if (a[i] != b[i]) - ++cnt; - return cnt <= 2; + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; } int find(int x) { - if (p[x] != x) p[x] = find(p[x]); + if (p[x] != x) { + p[x] = find(p[x]); + } return p[x]; } + +private: + vector p, size; +}; + +class Solution { +public: + int numSimilarGroups(vector& strs) { + int n = strs.size(), m = strs[0].size(); + int cnt = n; + UnionFind uf(n); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + int diff = 0; + for (int k = 0; k < m; ++k) { + diff += strs[i][k] != strs[j][k]; + } + if (diff <= 2 && uf.unite(i, j)) { + --cnt; + } + } + } + return cnt; + } }; ``` #### Go ```go -func numSimilarGroups(strs []string) int { - n := len(strs) +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { p := make([]int, n) + size := make([]int, n) for i := range p { p[i] = i + size[i] = 1 } - check := func(a, b string) bool { - cnt := 0 - for i := range a { - if a[i] != b[i] { - cnt++ - } - } - return cnt <= 2 + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) - } - return p[x] + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false } - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - if check(strs[i], strs[j]) { - p[find(i)] = find(j) - } - } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] } - ans := 0 - for i := 0; i < n; i++ { - if i == find(i) { - ans++ + return true +} + +func numSimilarGroups(strs []string) int { + n := len(strs) + uf := newUnionFind(n) + for i, s := range strs { + for j, t := range strs[:i] { + diff := 0 + for k := range s { + if s[k] != t[k] { + diff++ + } + } + if diff <= 2 && uf.union(i, j) { + n-- + } } } - return ans + return n +} +``` + +#### TypeScript + +```ts +class UnionFind { + private p: number[]; + private size: number[]; + + constructor(n: number) { + this.p = Array.from({ length: n }, (_, i) => i); + this.size = Array(n).fill(1); + } + + union(a: number, b: number): boolean { + const pa = this.find(a); + const pb = this.find(b); + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } +} + +function numSimilarGroups(strs: string[]): number { + const n = strs.length; + const m = strs[0].length; + const uf = new UnionFind(n); + let cnt = n; + for (let i = 0; i < n; ++i) { + for (let j = 0; j < i; ++j) { + let diff = 0; + for (let k = 0; k < m; ++k) { + if (strs[i][k] !== strs[j][k]) { + diff++; + } + } + if (diff <= 2 && uf.union(i, j)) { + cnt--; + } + } + } + return cnt; } ``` diff --git a/solution/0800-0899/0839.Similar String Groups/Solution.cpp b/solution/0800-0899/0839.Similar String Groups/Solution.cpp index fd8d47e0f343e..58d60374ca97b 100644 --- a/solution/0800-0899/0839.Similar String Groups/Solution.cpp +++ b/solution/0800-0899/0839.Similar String Groups/Solution.cpp @@ -1,32 +1,54 @@ -class Solution { +class UnionFind { public: - vector p; - - int numSimilarGroups(vector& strs) { - int n = strs.size(); - p.resize(n); - for (int i = 0; i < n; ++i) p[i] = i; - for (int i = 0; i < n; ++i) - for (int j = i + 1; j < n; ++j) - if (check(strs[i], strs[j])) - p[find(i)] = find(j); - int ans = 0; - for (int i = 0; i < n; ++i) - if (i == find(i)) - ++ans; - return ans; + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); } - bool check(string a, string b) { - int cnt = 0; - for (int i = 0; i < a.size(); ++i) - if (a[i] != b[i]) - ++cnt; - return cnt <= 2; + bool unite(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; + } + return true; } int find(int x) { - if (p[x] != x) p[x] = find(p[x]); + if (p[x] != x) { + p[x] = find(p[x]); + } return p[x]; } -}; \ No newline at end of file + +private: + vector p, size; +}; + +class Solution { +public: + int numSimilarGroups(vector& strs) { + int n = strs.size(), m = strs[0].size(); + int cnt = n; + UnionFind uf(n); + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + int diff = 0; + for (int k = 0; k < m; ++k) { + diff += strs[i][k] != strs[j][k]; + } + if (diff <= 2 && uf.unite(i, j)) { + --cnt; + } + } + } + return cnt; + } +}; diff --git a/solution/0800-0899/0839.Similar String Groups/Solution.go b/solution/0800-0899/0839.Similar String Groups/Solution.go index 7833d364f4345..c35924f2b36d2 100644 --- a/solution/0800-0899/0839.Similar String Groups/Solution.go +++ b/solution/0800-0899/0839.Similar String Groups/Solution.go @@ -1,37 +1,54 @@ -func numSimilarGroups(strs []string) int { - n := len(strs) +type unionFind struct { + p, size []int +} + +func newUnionFind(n int) *unionFind { p := make([]int, n) + size := make([]int, n) for i := range p { p[i] = i + size[i] = 1 } - check := func(a, b string) bool { - cnt := 0 - for i := range a { - if a[i] != b[i] { - cnt++ - } - } - return cnt <= 2 + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.p[x]) } - var find func(x int) int - find = func(x int) int { - if p[x] != x { - p[x] = find(p[x]) - } - return p[x] + return uf.p[x] +} + +func (uf *unionFind) union(a, b int) bool { + pa, pb := uf.find(a), uf.find(b) + if pa == pb { + return false } - for i := 0; i < n; i++ { - for j := i + 1; j < n; j++ { - if check(strs[i], strs[j]) { - p[find(i)] = find(j) - } - } + if uf.size[pa] > uf.size[pb] { + uf.p[pb] = pa + uf.size[pa] += uf.size[pb] + } else { + uf.p[pa] = pb + uf.size[pb] += uf.size[pa] } - ans := 0 - for i := 0; i < n; i++ { - if i == find(i) { - ans++ + return true +} + +func numSimilarGroups(strs []string) int { + n := len(strs) + uf := newUnionFind(n) + for i, s := range strs { + for j, t := range strs[:i] { + diff := 0 + for k := range s { + if s[k] != t[k] { + diff++ + } + } + if diff <= 2 && uf.union(i, j) { + n-- + } } } - return ans -} \ No newline at end of file + return n +} diff --git a/solution/0800-0899/0839.Similar String Groups/Solution.java b/solution/0800-0899/0839.Similar String Groups/Solution.java index b0ddcc219b9b5..fda04e4f5398c 100644 --- a/solution/0800-0899/0839.Similar String Groups/Solution.java +++ b/solution/0800-0899/0839.Similar String Groups/Solution.java @@ -1,43 +1,57 @@ -class Solution { - private int[] p; +class UnionFind { + private final int[] p; + private final int[] size; - public int numSimilarGroups(String[] strs) { - int n = strs.length; + public UnionFind(int n) { p = new int[n]; + size = new int[n]; for (int i = 0; i < n; ++i) { p[i] = i; + size[i] = 1; } - for (int i = 0; i < n; ++i) { - for (int j = i + 1; j < n; ++j) { - if (check(strs[i], strs[j])) { - p[find(i)] = find(j); - } - } - } - int res = 0; - for (int i = 0; i < n; ++i) { - if (i == find(i)) { - ++res; - } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); } - return res; + return p[x]; } - private boolean check(String a, String b) { - int cnt = 0; - int n = a.length(); - for (int i = 0; i < n; ++i) { - if (a.charAt(i) != b.charAt(i)) { - ++cnt; - } + public boolean union(int a, int b) { + int pa = find(a), pb = find(b); + if (pa == pb) { + return false; + } + if (size[pa] > size[pb]) { + p[pb] = pa; + size[pa] += size[pb]; + } else { + p[pa] = pb; + size[pb] += size[pa]; } - return cnt <= 2; + return true; } +} - private int find(int x) { - if (p[x] != x) { - p[x] = find(p[x]); +class Solution { + public int numSimilarGroups(String[] strs) { + int n = strs.length, m = strs[0].length(); + UnionFind uf = new UnionFind(n); + int cnt = n; + for (int i = 0; i < n; ++i) { + for (int j = 0; j < i; ++j) { + int diff = 0; + for (int k = 0; k < m; ++k) { + if (strs[i].charAt(k) != strs[j].charAt(k)) { + ++diff; + } + } + if (diff <= 2 && uf.union(i, j)) { + --cnt; + } + } } - return p[x]; + return cnt; } -} \ No newline at end of file +} diff --git a/solution/0800-0899/0839.Similar String Groups/Solution.py b/solution/0800-0899/0839.Similar String Groups/Solution.py index 981ade74b1ab9..603c38737b77f 100644 --- a/solution/0800-0899/0839.Similar String Groups/Solution.py +++ b/solution/0800-0899/0839.Similar String Groups/Solution.py @@ -1,14 +1,32 @@ +class UnionFind: + def __init__(self, n): + self.p = list(range(n)) + self.size = [1] * n + + def find(self, x): + if self.p[x] != x: + self.p[x] = self.find(self.p[x]) + return self.p[x] + + def union(self, a, b): + pa, pb = self.find(a), self.find(b) + if pa == pb: + return False + if self.size[pa] > self.size[pb]: + self.p[pb] = pa + self.size[pa] += self.size[pb] + else: + self.p[pa] = pb + self.size[pb] += self.size[pa] + return True + + class Solution: def numSimilarGroups(self, strs: List[str]) -> int: - def find(x): - if p[x] != x: - p[x] = find(p[x]) - return p[x] - - n, l = len(strs), len(strs[0]) - p = list(range(n)) - for i in range(n): - for j in range(i + 1, n): - if sum(strs[i][k] != strs[j][k] for k in range(l)) <= 2: - p[find(i)] = find(j) - return sum(i == find(i) for i in range(n)) + n, m = len(strs), len(strs[0]) + uf = UnionFind(n) + for i, s in enumerate(strs): + for j, t in enumerate(strs[:i]): + if sum(s[k] != t[k] for k in range(m)) <= 2 and uf.union(i, j): + n -= 1 + return n diff --git a/solution/0800-0899/0839.Similar String Groups/Solution.ts b/solution/0800-0899/0839.Similar String Groups/Solution.ts new file mode 100644 index 0000000000000..61ea5051f3b0b --- /dev/null +++ b/solution/0800-0899/0839.Similar String Groups/Solution.ts @@ -0,0 +1,53 @@ +class UnionFind { + private p: number[]; + private size: number[]; + + constructor(n: number) { + this.p = Array.from({ length: n }, (_, i) => i); + this.size = Array(n).fill(1); + } + + union(a: number, b: number): boolean { + const pa = this.find(a); + const pb = this.find(b); + if (pa === pb) { + return false; + } + if (this.size[pa] > this.size[pb]) { + this.p[pb] = pa; + this.size[pa] += this.size[pb]; + } else { + this.p[pa] = pb; + this.size[pb] += this.size[pa]; + } + return true; + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } +} + +function numSimilarGroups(strs: string[]): number { + const n = strs.length; + const m = strs[0].length; + const uf = new UnionFind(n); + let cnt = n; + for (let i = 0; i < n; ++i) { + for (let j = 0; j < i; ++j) { + let diff = 0; + for (let k = 0; k < m; ++k) { + if (strs[i][k] !== strs[j][k]) { + diff++; + } + } + if (diff <= 2 && uf.union(i, j)) { + cnt--; + } + } + } + return cnt; +} diff --git a/solution/0800-0899/0840.Magic Squares In Grid/README.md b/solution/0800-0899/0840.Magic Squares In Grid/README.md index 5ebc062a30c0f..338eb194fb833 100644 --- a/solution/0800-0899/0840.Magic Squares In Grid/README.md +++ b/solution/0800-0899/0840.Magic Squares In Grid/README.md @@ -278,9 +278,9 @@ function numMagicSquaresInside(grid: number[][]): number { if (i + 3 > m || j + 3 > n) { return 0; } - const cnt: number[] = new Array(16).fill(0); - const row: number[] = new Array(3).fill(0); - const col: number[] = new Array(3).fill(0); + const cnt: number[] = Array(16).fill(0); + const row: number[] = Array(3).fill(0); + const col: number[] = Array(3).fill(0); let [a, b] = [0, 0]; for (let x = i; x < i + 3; ++x) { for (let y = j; y < j + 3; ++y) { diff --git a/solution/0800-0899/0840.Magic Squares In Grid/README_EN.md b/solution/0800-0899/0840.Magic Squares In Grid/README_EN.md index 3739419c53c8b..5585d83cb0877 100644 --- a/solution/0800-0899/0840.Magic Squares In Grid/README_EN.md +++ b/solution/0800-0899/0840.Magic Squares In Grid/README_EN.md @@ -62,7 +62,11 @@ In total, there is only one magic square inside the given grid. -### Solution 1 +### Solution 1: Enumeration + +We directly enumerate the top-left coordinates $(i, j)$ of each $3 \times 3$ sub-matrix, then check whether the sub-matrix satisfies the "magic square" condition. If it does, increment the answer by one. After enumeration, return the answer. + +Time complexity is $O(m \times n)$, where $m$ and $n$ are the number of rows and columns of the matrix, respectively. Space complexity is $O(1)$. @@ -270,9 +274,9 @@ function numMagicSquaresInside(grid: number[][]): number { if (i + 3 > m || j + 3 > n) { return 0; } - const cnt: number[] = new Array(16).fill(0); - const row: number[] = new Array(3).fill(0); - const col: number[] = new Array(3).fill(0); + const cnt: number[] = Array(16).fill(0); + const row: number[] = Array(3).fill(0); + const col: number[] = Array(3).fill(0); let [a, b] = [0, 0]; for (let x = i; x < i + 3; ++x) { for (let y = j; y < j + 3; ++y) { diff --git a/solution/0800-0899/0840.Magic Squares In Grid/Solution.ts b/solution/0800-0899/0840.Magic Squares In Grid/Solution.ts index a6489d609510f..0f8bd8e0a0f3e 100644 --- a/solution/0800-0899/0840.Magic Squares In Grid/Solution.ts +++ b/solution/0800-0899/0840.Magic Squares In Grid/Solution.ts @@ -5,9 +5,9 @@ function numMagicSquaresInside(grid: number[][]): number { if (i + 3 > m || j + 3 > n) { return 0; } - const cnt: number[] = new Array(16).fill(0); - const row: number[] = new Array(3).fill(0); - const col: number[] = new Array(3).fill(0); + const cnt: number[] = Array(16).fill(0); + const row: number[] = Array(3).fill(0); + const col: number[] = Array(3).fill(0); let [a, b] = [0, 0]; for (let x = i; x < i + 3; ++x) { for (let y = j; y < j + 3; ++y) { diff --git a/solution/3100-3199/3132.Find the Integer Added to Array II/README.md b/solution/3100-3199/3132.Find the Integer Added to Array II/README.md index 5fa21531a3008..228f5937fd5c6 100644 --- a/solution/3100-3199/3132.Find the Integer Added to Array II/README.md +++ b/solution/3100-3199/3132.Find the Integer Added to Array II/README.md @@ -109,11 +109,12 @@ class Solution: nums1.sort() nums2.sort() - return min( - x - for x in (nums2[0] - nums1[0], nums2[0] - nums1[1], nums2[0] - nums1[2]) - if f(x) - ) + ans = inf + for i in range(3): + x = nums2[0] - nums1[i] + if f(x): + ans = min(ans, x) + return ans ``` #### Java diff --git a/solution/3100-3199/3132.Find the Integer Added to Array II/README_EN.md b/solution/3100-3199/3132.Find the Integer Added to Array II/README_EN.md index 14781b2a25c71..ce250b7c63e16 100644 --- a/solution/3100-3199/3132.Find the Integer Added to Array II/README_EN.md +++ b/solution/3100-3199/3132.Find the Integer Added to Array II/README_EN.md @@ -107,11 +107,12 @@ class Solution: nums1.sort() nums2.sort() - return min( - x - for x in (nums2[0] - nums1[0], nums2[0] - nums1[1], nums2[0] - nums1[2]) - if f(x) - ) + ans = inf + for i in range(3): + x = nums2[0] - nums1[i] + if f(x): + ans = min(ans, x) + return ans ``` #### Java diff --git a/solution/3100-3199/3132.Find the Integer Added to Array II/Solution.py b/solution/3100-3199/3132.Find the Integer Added to Array II/Solution.py index a4e5a4725964e..5cdd11fd40519 100644 --- a/solution/3100-3199/3132.Find the Integer Added to Array II/Solution.py +++ b/solution/3100-3199/3132.Find the Integer Added to Array II/Solution.py @@ -12,8 +12,9 @@ def f(x: int) -> bool: nums1.sort() nums2.sort() - return min( - x - for x in (nums2[0] - nums1[0], nums2[0] - nums1[1], nums2[0] - nums1[2]) - if f(x) - ) + ans = inf + for i in range(3): + x = nums2[0] - nums1[i] + if f(x): + ans = min(ans, x) + return ans