
2025-09-19:属性图。用go语言,给出一个大小为 n×m 的整数矩阵 properties 和一个整数 k。
定义一个函数,用来计算两个行向量之间不同元素的交集大小(即两行中共同出现的不重复整数的个数)。
把每一行看作图中的一个顶点,若任意两行之间共有的不同整数数目不少于 k,则在对应的两个顶点之间连一条无向边。
求该无向图中连通块(连通分量)的总数,并将该数作为结果返回。
1 <= n == properties.length <= 100。
1 <= m == properties[i].length <= 100。
1 <= properties[i][j] <= 100。
1 <= k <= m。
输入: properties = [[1,2],[1,1],[3,4],[4,5],[5,6],[7,7]], k = 1。
输出: 3。
解释:
生成的图有 3 个连通分量:

题目来自力扣3493。
n x m 的矩阵 properties,其中每一行是一个属性集合(可能有重复元素)。k,则在这两个顶点之间添加一条无向边。n(行数)的切片 sets,其中每个元素是一个集合(这里用 map[int]bool 实现)。properties[i],对于每个元素,将其添加到对应的集合 sets[i] 中。这样,sets[i] 就是第 i 行的不同整数集合。u,大小为 n(即顶点数)。初始时每个顶点自成一个连通分量,所以连通分量数 cc 为 n。find(x):查找顶点 x 的根(代表元),同时进行路径压缩。merge(from, to):合并两个顶点所在的集合(如果它们不在同一集合中),并减少连通分量计数 cc。(i, j)(其中 i 从 0 到 n-1,j 从 0 到 i-1),计算它们的集合 sets[i] 和 sets[j] 的交集大小。sets[j]),检查每个元素是否在 sets[i] 中存在。统计存在的个数(即交集大小)。cnt >= k,则调用 u.merge(i, j) 合并这两个顶点(即合并它们所在的连通分量)。u.cc 就是答案。m 个元素(m<=100),所以预处理时间为 O(n*m)。O(n^2) 对(n<=100,所以最多10000对)。m,即100),所以每对操作是 O(m)。O(n*m + n^2 * m) = O(n^2 * m)。代入最大数值(n=100, m=100)约为100万次操作,在Go中是可接受的。n 个集合,每个集合最多 m 个元素,所以空间为 O(n*m)。O(n) 的父数组。O(n*m)。.
package main
import (
"fmt"
)
type uf struct {
fa []int
cc int
}
func newUnionFind(n int) uf {
fa := make([]int, n)
for i := range fa {
fa[i] = i
}
return uf{fa, n}
}
func (u uf) find(x int) int {
if u.fa[x] != x {
u.fa[x] = u.find(u.fa[x])
}
return u.fa[x]
}
func (u *uf) merge(from, to int) {
x, y := u.find(from), u.find(to)
if x == y {
return
}
u.fa[x] = y
u.cc--
}
func numberOfComponents(properties [][]int, k int)int {
sets := make([]map[int]bool, len(properties))
for i, a := range properties {
sets[i] = map[int]bool{}
for _, x := range a {
sets[i][x] = true
}
}
u := newUnionFind(len(properties))
for i, a := range sets {
for j, b := range sets[:i] {
cnt := 0
for x := range b {
if a[x] {
cnt++
}
}
if cnt >= k {
u.merge(i, j)
}
}
}
return u.cc
}
func main() {
properties := [][]int{{1, 2}, {1, 1}, {3, 4}, {4, 5}, {5, 6}, {7, 7}}
k := 1
result := numberOfComponents(properties, k)
fmt.Println(result)
}

.
# -*-coding:utf-8-*-
class UF:
def __init__(self, n):
self.fa = list(range(n))
self.cc = n
def find(self, x):
if self.fa[x] != x:
self.fa[x] = self.find(self.fa[x])
return self.fa[x]
def merge(self, from_, to):
x = self.find(from_)
y = self.find(to)
if x == y:
return
self.fa[x] = y
self.cc -= 1
def number_of_components(properties, k):
sets = []
for a in properties:
sets.append(set(a))
n = len(properties)
u = UF(n)
for i in range(n):
a = sets[i]
for j in range(i):
b = sets[j]
cnt = len(a & b) # 计算交集大小
if cnt >= k:
u.merge(i, j)
return u.cc
def main():
properties = [[1, 2], [1, 1], [3, 4], [4, 5], [5, 6], [7, 7]]
k = 1
result = number_of_components(properties, k)
print(result)
if __name__ == "__main__":
main()
我们相信Go语言和算法为普通开发者提供了困境的“面试利器”,并致力于分享全面的编程知识。在这里,您可以找到最新的Go语言教程、算法解析、提升面试竞争力的秘籍以及行业动态。 欢迎关注“福大大架构师每日一题”,发消息可获得面试资料,让 Go 语言和算法助力您的职业发展