Files
leetcode/data-structure/ds-set.go
T
2026-07-20 19:57:25 +08:00

92 lines
2.1 KiB
Go

package ds
// ds-set.go
// 泛型集合,基于 map[T]struct{}。T 约束为 comparable。
// Add/Remove/Contains 均 O(1) 均摊。支持并集/交集/差集。
// 比 map[T]bool 更省内存(空结构体不占空间),语义也更清晰。
// Set 泛型集合,零值不可直接用(map 零值不能写),必须用 NewSet。
type Set[T comparable] struct {
m map[T]struct{}
}
// NewSet 创建空集合。
func NewSet[T comparable]() *Set[T] {
return &Set[T]{m: make(map[T]struct{})}
}
// NewSetFrom 从切片创建集合,自动去重。
func NewSetFrom[T comparable](vals []T) *Set[T] {
s := NewSet[T]()
for _, v := range vals {
s.m[v] = struct{}{}
}
return s
}
// Add 添加元素,已存在则无操作。
func (s *Set[T]) Add(v T) { s.m[v] = struct{}{} }
// Remove 删除元素,不存在则无操作。
func (s *Set[T]) Remove(v T) { delete(s.m, v) }
// Contains 是否包含元素。
func (s *Set[T]) Contains(v T) bool {
_, ok := s.m[v]
return ok
}
// Len 元素个数。
func (s *Set[T]) Len() int { return len(s.m) }
// Empty 是否为空。
func (s *Set[T]) Empty() bool { return len(s.m) == 0 }
// ToSlice 转为切片。map 遍历顺序无序,如需稳定顺序需自行排序。
func (s *Set[T]) ToSlice() []T {
out := make([]T, 0, len(s.m))
for v := range s.m {
out = append(out, v)
}
return out
}
// Union 并集:返回新集合,包含 s 和 other 的所有元素。
func (s *Set[T]) Union(other *Set[T]) *Set[T] {
r := NewSet[T]()
for v := range s.m {
r.m[v] = struct{}{}
}
for v := range other.m {
r.m[v] = struct{}{}
}
return r
}
// Intersect 交集:返回新集合,仅包含 s 和 other 都有的元素。
func (s *Set[T]) Intersect(other *Set[T]) *Set[T] {
r := NewSet[T]()
// 遍历较小集合,降低常数
small, big := s, other
if small.Len() > big.Len() {
small, big = big, small
}
for v := range small.m {
if _, ok := big.m[v]; ok {
r.m[v] = struct{}{}
}
}
return r
}
// Difference 差集:返回新集合,包含在 s 中但不在 other 中的元素。
func (s *Set[T]) Difference(other *Set[T]) *Set[T] {
r := NewSet[T]()
for v := range s.m {
if _, ok := other.m[v]; !ok {
r.m[v] = struct{}{}
}
}
return r
}