diff --git a/solution/3600-3699/3608.Minimum Time for K Connected Components/README.md b/solution/3600-3699/3608.Minimum Time for K Connected Components/README.md index 72c59a814d00d..b9234b9e3ff98 100644 --- a/solution/3600-3699/3608.Minimum Time for K Connected Components/README.md +++ b/solution/3600-3699/3608.Minimum Time for K Connected Components/README.md @@ -107,32 +107,306 @@ tags: -### 方法一 +### 方法一:并查集 + +我们可以将边按时间从小到大排序,然后从时间最大的边开始依次将边加入图中,同时使用并查集维护当前图的连通分量数量。当连通分量数量小于 $k$ 时,说明当前时间即为所求的最小时间。 + +时间复杂度 $O(n \times \alpha(n))$,空间复杂度 $O(n)$,其中 $\alpha$ 是反阿克曼函数。 #### 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 minTime(self, n: int, edges: List[List[int]], k: int) -> int: + edges.sort(key=lambda x: x[2]) + uf = UnionFind(n) + cnt = n + for u, v, t in edges[::-1]: + if uf.union(u, v): + cnt -= 1 + if cnt < k: + return t + return 0 ``` #### 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); + int 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 int minTime(int n, int[][] edges, int k) { + Arrays.sort(edges, (a, b) -> Integer.compare(a[2], b[2])); + + UnionFind uf = new UnionFind(n); + int cnt = n; + + for (int i = edges.length - 1; i >= 0; i--) { + int u = edges[i][0]; + int v = edges[i][1]; + int t = edges[i][2]; + + if (uf.union(u, v)) { + if (--cnt < k) { + return t; + } + } + } + return 0; + } +} ``` #### C++ ```cpp - +class UnionFind { +public: + vector p; + vector size; + + UnionFind(int n) { + p.resize(n); + size.resize(n, 1); + for (int i = 0; i < n; i++) { + p[i] = i; + } + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + bool unite(int a, int b) { + int pa = find(a); + int 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: + int minTime(int n, vector>& edges, int k) { + sort(edges.begin(), edges.end(), [](const vector& a, const vector& b) { + return a[2] < b[2]; + }); + + UnionFind uf(n); + int cnt = n; + + for (int i = edges.size() - 1; i >= 0; i--) { + int u = edges[i][0]; + int v = edges[i][1]; + int t = edges[i][2]; + + if (uf.unite(u, v)) { + cnt--; + if (cnt < k) { + return t; + } + } + } + return 0; + } +}; ``` #### Go ```go +type UnionFind struct { + p []int + size []int +} + +func NewUnionFind(n int) *UnionFind { + uf := &UnionFind{ + p: make([]int, n), + size: make([]int, n), + } + for i := 0; i < n; i++ { + uf.p[i] = i + uf.size[i] = 1 + } + return uf +} + +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 := uf.find(a) + pb := 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 minTime(n int, edges [][]int, k int) int { + sort.Slice(edges, func(i, j int) bool { + return edges[i][2] < edges[j][2] + }) + + uf := NewUnionFind(n) + cnt := n + + for i := len(edges) - 1; i >= 0; i-- { + u := edges[i][0] + v := edges[i][1] + t := edges[i][2] + + if uf.union(u, v) { + cnt-- + if cnt < k { + return t + } + } + } + return 0 +} +``` +#### TypeScript + +```ts +class UnionFind { + p: number[]; + size: number[]; + + constructor(n: number) { + this.p = Array.from({ length: n }, (_, 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 = 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; + } +} + +function minTime(n: number, edges: number[][], k: number): number { + edges.sort((a, b) => a[2] - b[2]); + + const uf = new UnionFind(n); + let cnt = n; + + for (let i = edges.length - 1; i >= 0; i--) { + const [u, v, t] = edges[i]; + + if (uf.union(u, v)) { + if (--cnt < k) { + return t; + } + } + } + + return 0; +} ``` diff --git a/solution/3600-3699/3608.Minimum Time for K Connected Components/README_EN.md b/solution/3600-3699/3608.Minimum Time for K Connected Components/README_EN.md index 7146a2ccc41a5..bb227c407409e 100644 --- a/solution/3600-3699/3608.Minimum Time for K Connected Components/README_EN.md +++ b/solution/3600-3699/3608.Minimum Time for K Connected Components/README_EN.md @@ -104,32 +104,306 @@ tags: -### Solution 1 +### Solution 1: Union-Find + +We can sort the edges by time in ascending order, then starting from the edge with the largest time, add edges to the graph one by one, while using a union-find data structure to maintain the number of connected components in the current graph. When the number of connected components is less than $k$, the current time is the minimum time we are looking for. + +The time complexity is $O(n \times \alpha(n))$, and the space complexity is $O(n)$, where $\alpha$ is the inverse 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 minTime(self, n: int, edges: List[List[int]], k: int) -> int: + edges.sort(key=lambda x: x[2]) + uf = UnionFind(n) + cnt = n + for u, v, t in edges[::-1]: + if uf.union(u, v): + cnt -= 1 + if cnt < k: + return t + return 0 ``` #### 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); + int 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 int minTime(int n, int[][] edges, int k) { + Arrays.sort(edges, (a, b) -> Integer.compare(a[2], b[2])); + + UnionFind uf = new UnionFind(n); + int cnt = n; + + for (int i = edges.length - 1; i >= 0; i--) { + int u = edges[i][0]; + int v = edges[i][1]; + int t = edges[i][2]; + + if (uf.union(u, v)) { + if (--cnt < k) { + return t; + } + } + } + return 0; + } +} ``` #### C++ ```cpp - +class UnionFind { +public: + vector p; + vector size; + + UnionFind(int n) { + p.resize(n); + size.resize(n, 1); + for (int i = 0; i < n; i++) { + p[i] = i; + } + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + bool unite(int a, int b) { + int pa = find(a); + int 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: + int minTime(int n, vector>& edges, int k) { + sort(edges.begin(), edges.end(), [](const vector& a, const vector& b) { + return a[2] < b[2]; + }); + + UnionFind uf(n); + int cnt = n; + + for (int i = edges.size() - 1; i >= 0; i--) { + int u = edges[i][0]; + int v = edges[i][1]; + int t = edges[i][2]; + + if (uf.unite(u, v)) { + cnt--; + if (cnt < k) { + return t; + } + } + } + return 0; + } +}; ``` #### Go ```go +type UnionFind struct { + p []int + size []int +} + +func NewUnionFind(n int) *UnionFind { + uf := &UnionFind{ + p: make([]int, n), + size: make([]int, n), + } + for i := 0; i < n; i++ { + uf.p[i] = i + uf.size[i] = 1 + } + return uf +} + +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 := uf.find(a) + pb := 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 minTime(n int, edges [][]int, k int) int { + sort.Slice(edges, func(i, j int) bool { + return edges[i][2] < edges[j][2] + }) + + uf := NewUnionFind(n) + cnt := n + + for i := len(edges) - 1; i >= 0; i-- { + u := edges[i][0] + v := edges[i][1] + t := edges[i][2] + + if uf.union(u, v) { + cnt-- + if cnt < k { + return t + } + } + } + return 0 +} +``` +#### TypeScript + +```ts +class UnionFind { + p: number[]; + size: number[]; + + constructor(n: number) { + this.p = Array.from({ length: n }, (_, 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 = 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; + } +} + +function minTime(n: number, edges: number[][], k: number): number { + edges.sort((a, b) => a[2] - b[2]); + + const uf = new UnionFind(n); + let cnt = n; + + for (let i = edges.length - 1; i >= 0; i--) { + const [u, v, t] = edges[i]; + + if (uf.union(u, v)) { + if (--cnt < k) { + return t; + } + } + } + + return 0; +} ``` diff --git a/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.cpp b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.cpp new file mode 100644 index 0000000000000..86d08b6d5d132 --- /dev/null +++ b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.cpp @@ -0,0 +1,63 @@ +class UnionFind { +public: + vector p; + vector size; + + UnionFind(int n) { + p.resize(n); + size.resize(n, 1); + for (int i = 0; i < n; i++) { + p[i] = i; + } + } + + int find(int x) { + if (p[x] != x) { + p[x] = find(p[x]); + } + return p[x]; + } + + bool unite(int a, int b) { + int pa = find(a); + int 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: + int minTime(int n, vector>& edges, int k) { + sort(edges.begin(), edges.end(), [](const vector& a, const vector& b) { + return a[2] < b[2]; + }); + + UnionFind uf(n); + int cnt = n; + + for (int i = edges.size() - 1; i >= 0; i--) { + int u = edges[i][0]; + int v = edges[i][1]; + int t = edges[i][2]; + + if (uf.unite(u, v)) { + cnt--; + if (cnt < k) { + return t; + } + } + } + return 0; + } +}; diff --git a/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.go b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.go new file mode 100644 index 0000000000000..f57f0ea1bcc0d --- /dev/null +++ b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.go @@ -0,0 +1,63 @@ +type UnionFind struct { + p []int + size []int +} + +func NewUnionFind(n int) *UnionFind { + uf := &UnionFind{ + p: make([]int, n), + size: make([]int, n), + } + for i := 0; i < n; i++ { + uf.p[i] = i + uf.size[i] = 1 + } + return uf +} + +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 := uf.find(a) + pb := 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 minTime(n int, edges [][]int, k int) int { + sort.Slice(edges, func(i, j int) bool { + return edges[i][2] < edges[j][2] + }) + + uf := NewUnionFind(n) + cnt := n + + for i := len(edges) - 1; i >= 0; i-- { + u := edges[i][0] + v := edges[i][1] + t := edges[i][2] + + if uf.union(u, v) { + cnt-- + if cnt < k { + return t + } + } + } + return 0 +} diff --git a/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.java b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.java new file mode 100644 index 0000000000000..d19aabac4d916 --- /dev/null +++ b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.java @@ -0,0 +1,59 @@ +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); + int 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 int minTime(int n, int[][] edges, int k) { + Arrays.sort(edges, (a, b) -> Integer.compare(a[2], b[2])); + + UnionFind uf = new UnionFind(n); + int cnt = n; + + for (int i = edges.length - 1; i >= 0; i--) { + int u = edges[i][0]; + int v = edges[i][1]; + int t = edges[i][2]; + + if (uf.union(u, v)) { + if (--cnt < k) { + return t; + } + } + } + return 0; + } +} diff --git a/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.py b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.py new file mode 100644 index 0000000000000..7365fc73f2d02 --- /dev/null +++ b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.py @@ -0,0 +1,34 @@ +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 minTime(self, n: int, edges: List[List[int]], k: int) -> int: + edges.sort(key=lambda x: x[2]) + uf = UnionFind(n) + cnt = n + for u, v, t in edges[::-1]: + if uf.union(u, v): + cnt -= 1 + if cnt < k: + return t + return 0 diff --git a/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.ts b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.ts new file mode 100644 index 0000000000000..7f0704bebd543 --- /dev/null +++ b/solution/3600-3699/3608.Minimum Time for K Connected Components/Solution.ts @@ -0,0 +1,50 @@ +class UnionFind { + p: number[]; + size: number[]; + + constructor(n: number) { + this.p = Array.from({ length: n }, (_, 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 = 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; + } +} + +function minTime(n: number, edges: number[][], k: number): number { + edges.sort((a, b) => a[2] - b[2]); + + const uf = new UnionFind(n); + let cnt = n; + + for (let i = edges.length - 1; i >= 0; i--) { + const [u, v, t] = edges[i]; + + if (uf.union(u, v)) { + if (--cnt < k) { + return t; + } + } + } + + return 0; +}