From bdc847e8c571b47a462b0ae0340e30ee1c096778 Mon Sep 17 00:00:00 2001 From: yanglbme Date: Tue, 21 Nov 2023 19:02:46 +0800 Subject: [PATCH] feat: add solutions to lc problem: No.1627 No.1627.Graph Connectivity With Threshold --- .../README.md | 245 +++++++++++++++++- .../README_EN.md | 243 +++++++++++++++++ .../Solution.cpp | 50 ++++ .../Solution.go | 49 ++++ .../Solution.java | 51 ++++ .../Solution.py | 32 +++ .../Solution.ts | 42 +++ 7 files changed, 711 insertions(+), 1 deletion(-) create mode 100644 solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.cpp create mode 100644 solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.go create mode 100644 solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.java create mode 100644 solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.py create mode 100644 solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.ts diff --git a/solution/1600-1699/1627.Graph Connectivity With Threshold/README.md b/solution/1600-1699/1627.Graph Connectivity With Threshold/README.md index 838b60916bcec..42a8a1272fd94 100644 --- a/solution/1600-1699/1627.Graph Connectivity With Threshold/README.md +++ b/solution/1600-1699/1627.Graph Connectivity With Threshold/README.md @@ -84,6 +84,12 @@ +**方法一:并查集** + +我们可以枚举 $z$ 以及 $z$ 的倍数,用并查集将它们连通起来。这样,对于每个查询 $[a, b]$,我们只需要判断 $a$ 和 $b$ 是否在同一个连通块中即可。 + +时间复杂度 $O(n \times \log n \time (\alpha(n) + q))$,空间复杂度 $O(n)$。其中 $n$ 和 $q$ 分别是节点数和查询数,而 $\alpha$ 是阿克曼函数的反函数。 + ### **Python3** @@ -91,7 +97,38 @@ ```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 areConnected( + self, n: int, threshold: int, queries: List[List[int]] + ) -> List[bool]: + uf = UnionFind(n + 1) + for a in range(threshold + 1, n + 1): + for b in range(a + a, n + 1, a): + uf.union(a, b) + return [uf.find(a) == uf.find(b) for a, b in queries] ``` ### **Java** @@ -99,7 +136,213 @@ ```java +class UnionFind { + private int[] p; + private int[] size; + + 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; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + 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 true; + } +} + +class Solution { + public List areConnected(int n, int threshold, int[][] queries) { + UnionFind uf = new UnionFind(n + 1); + for (int a = threshold + 1; a <= n; ++a) { + for (int b = a + a; b <= n; b += a) { + uf.union(a, b); + } + } + List ans = new ArrayList<>(); + for (var q : queries) { + ans.add(uf.find(q[0]) == uf.find(q[1])); + } + return ans; + } +} +``` + +### **C++** + +```cpp +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + 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]); + } + return p[x]; + } + +private: + vector p, size; +}; + +class Solution { +public: + vector areConnected(int n, int threshold, vector>& queries) { + UnionFind uf(n + 1); + for (int a = threshold + 1; a <= n; ++a) { + for (int b = a + a; b <= n; b += a) { + uf.unite(a, b); + } + } + vector ans; + for (auto& q : queries) { + ans.push_back(uf.find(q[0]) == uf.find(q[1])); + } + return ans; + } +}; +``` + +### **Go** + +```go +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 + } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.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 + } + 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] + } + return true +} + +func areConnected(n int, threshold int, queries [][]int) []bool { + uf := newUnionFind(n + 1) + for a := threshold + 1; a <= n; a++ { + for b := a + a; b <= n; b += a { + uf.union(a, b) + } + } + ans := make([]bool, len(queries)) + for i, q := range queries { + ans[i] = uf.find(q[0]) == uf.find(q[1]) + } + return ans +} +``` +### **TypeScript** + +```ts +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), 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; + } +} + +function areConnected(n: number, threshold: number, queries: number[][]): boolean[] { + const uf = new UnionFind(n + 1); + for (let a = threshold + 1; a <= n; ++a) { + for (let b = a * 2; b <= n; b += a) { + uf.union(a, b); + } + } + return queries.map(([a, b]) => uf.find(a) === uf.find(b)); +} ``` ### **...** diff --git a/solution/1600-1699/1627.Graph Connectivity With Threshold/README_EN.md b/solution/1600-1699/1627.Graph Connectivity With Threshold/README_EN.md index 6479a0d1153d4..9e3beb9666636 100644 --- a/solution/1600-1699/1627.Graph Connectivity With Threshold/README_EN.md +++ b/solution/1600-1699/1627.Graph Connectivity With Threshold/README_EN.md @@ -68,18 +68,261 @@ Please notice that there can be multiple queries for the same pair of nodes [x, ## Solutions +**Solution 1: Union-Find** + +We can enumerate $z$ and its multiples, and use union-find to connect them. In this way, for each query $[a, b]$, we only need to determine whether $a$ and $b$ are in the same connected component. + +The time complexity is $O(n \times \log n \times (\alpha(n) + q))$, and the space complexity is $O(n)$. Here, $n$ and $q$ are the number of nodes and queries, respectively, and $\alpha$ is the inverse function of the Ackermann function. + ### **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 areConnected( + self, n: int, threshold: int, queries: List[List[int]] + ) -> List[bool]: + uf = UnionFind(n + 1) + for a in range(threshold + 1, n + 1): + for b in range(a + a, n + 1, a): + uf.union(a, b) + return [uf.find(a) == uf.find(b) for a, b in queries] ``` ### **Java** ```java +class UnionFind { + private int[] p; + private int[] size; + + 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; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + 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 true; + } +} + +class Solution { + public List areConnected(int n, int threshold, int[][] queries) { + UnionFind uf = new UnionFind(n + 1); + for (int a = threshold + 1; a <= n; ++a) { + for (int b = a + a; b <= n; b += a) { + uf.union(a, b); + } + } + List ans = new ArrayList<>(); + for (var q : queries) { + ans.add(uf.find(q[0]) == uf.find(q[1])); + } + return ans; + } +} +``` + +### **C++** + +```cpp +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + 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]); + } + return p[x]; + } + +private: + vector p, size; +}; + +class Solution { +public: + vector areConnected(int n, int threshold, vector>& queries) { + UnionFind uf(n + 1); + for (int a = threshold + 1; a <= n; ++a) { + for (int b = a + a; b <= n; b += a) { + uf.unite(a, b); + } + } + vector ans; + for (auto& q : queries) { + ans.push_back(uf.find(q[0]) == uf.find(q[1])); + } + return ans; + } +}; +``` + +### **Go** + +```go +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 + } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.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 + } + 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] + } + return true +} + +func areConnected(n int, threshold int, queries [][]int) []bool { + uf := newUnionFind(n + 1) + for a := threshold + 1; a <= n; a++ { + for b := a + a; b <= n; b += a { + uf.union(a, b) + } + } + ans := make([]bool, len(queries)) + for i, q := range queries { + ans[i] = uf.find(q[0]) == uf.find(q[1]) + } + return ans +} +``` + +### **TypeScript** + +```ts +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), 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; + } +} +function areConnected(n: number, threshold: number, queries: number[][]): boolean[] { + const uf = new UnionFind(n + 1); + for (let a = threshold + 1; a <= n; ++a) { + for (let b = a * 2; b <= n; b += a) { + uf.union(a, b); + } + } + return queries.map(([a, b]) => uf.find(a) === uf.find(b)); +} ``` ### **...** diff --git a/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.cpp b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.cpp new file mode 100644 index 0000000000000..fca098e75549b --- /dev/null +++ b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.cpp @@ -0,0 +1,50 @@ +class UnionFind { +public: + UnionFind(int n) { + p = vector(n); + size = vector(n, 1); + iota(p.begin(), p.end(), 0); + } + + 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]); + } + return p[x]; + } + +private: + vector p, size; +}; + +class Solution { +public: + vector areConnected(int n, int threshold, vector>& queries) { + UnionFind uf(n + 1); + for (int a = threshold + 1; a <= n; ++a) { + for (int b = a + a; b <= n; b += a) { + uf.unite(a, b); + } + } + vector ans; + for (auto& q : queries) { + ans.push_back(uf.find(q[0]) == uf.find(q[1])); + } + return ans; + } +}; \ No newline at end of file diff --git a/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.go b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.go new file mode 100644 index 0000000000000..d742d3725db2e --- /dev/null +++ b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.go @@ -0,0 +1,49 @@ +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 + } + return &unionFind{p, size} +} + +func (uf *unionFind) find(x int) int { + if uf.p[x] != x { + uf.p[x] = uf.find(uf.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 + } + 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] + } + return true +} + +func areConnected(n int, threshold int, queries [][]int) []bool { + uf := newUnionFind(n + 1) + for a := threshold + 1; a <= n; a++ { + for b := a + a; b <= n; b += a { + uf.union(a, b) + } + } + ans := make([]bool, len(queries)) + for i, q := range queries { + ans[i] = uf.find(q[0]) == uf.find(q[1]) + } + return ans +} \ No newline at end of file diff --git a/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.java b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.java new file mode 100644 index 0000000000000..ef41ff93b3271 --- /dev/null +++ b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.java @@ -0,0 +1,51 @@ +class UnionFind { + private int[] p; + private int[] size; + + 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; + } + } + + public int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + 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 true; + } +} + +class Solution { + public List areConnected(int n, int threshold, int[][] queries) { + UnionFind uf = new UnionFind(n + 1); + for (int a = threshold + 1; a <= n; ++a) { + for (int b = a + a; b <= n; b += a) { + uf.union(a, b); + } + } + List ans = new ArrayList<>(); + for (var q : queries) { + ans.add(uf.find(q[0]) == uf.find(q[1])); + } + return ans; + } +} \ No newline at end of file diff --git a/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.py b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.py new file mode 100644 index 0000000000000..500491f1ad98e --- /dev/null +++ b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.py @@ -0,0 +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 areConnected( + self, n: int, threshold: int, queries: List[List[int]] + ) -> List[bool]: + uf = UnionFind(n + 1) + for a in range(threshold + 1, n + 1): + for b in range(a + a, n + 1, a): + uf.union(a, b) + return [uf.find(a) == uf.find(b) for a, b in queries] diff --git a/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.ts b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.ts new file mode 100644 index 0000000000000..982bc0b403ba4 --- /dev/null +++ b/solution/1600-1699/1627.Graph Connectivity With Threshold/Solution.ts @@ -0,0 +1,42 @@ +class UnionFind { + p: number[]; + size: number[]; + constructor(n: number) { + this.p = Array(n) + .fill(0) + .map((_, i) => i); + this.size = Array(n).fill(1); + } + + find(x: number): number { + if (this.p[x] !== x) { + this.p[x] = this.find(this.p[x]); + } + return this.p[x]; + } + + union(a: number, b: number): boolean { + const [pa, pb] = [this.find(a), 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; + } +} + +function areConnected(n: number, threshold: number, queries: number[][]): boolean[] { + const uf = new UnionFind(n + 1); + for (let a = threshold + 1; a <= n; ++a) { + for (let b = a * 2; b <= n; b += a) { + uf.union(a, b); + } + } + return queries.map(([a, b]) => uf.find(a) === uf.find(b)); +}