【问题标题】:Best algorithm to compare a set with a collection of sets将集合与集合集合进行比较的最佳算法
【发布时间】:2012-09-24 06:30:14
【问题描述】:

在作为特定集合子集的有限集合中找到集合的最佳算法是什么?

例如,如果

A = {1, 2}
B = {2, 3, 4}
C = {3, 5}
D = {6}

和 X = {1, 2, 3, 5}

那么,A 和 C 是 X 的子集。

有没有一种算法可以在线性时间复杂度上做到这一点?

实现说明:集合的成员通常来自非常有限的范围,因此,使用 C++ bitset 来实现算法可能是一个好主意。不能吗?

编辑:集合中的集合数通常非常大于 X 中的元素数(在示例中)。有没有办法根据 X 中的元素数量来做到这一点?可能使用哈希什么的?

【问题讨论】:

  • 没有办法在真正的线性时间内做到这一点。测试一个集合是否包含另一个集合在技术上始终是二次时间,但是在实践中使用哈希表将使此类问题成为线性时间(如果集合具有合理的长度)。所以你的问题的答案是时间复杂度将是M*N*Q,如果 M 是集合的数量 (A-D),N 是这些集合中最大的集合的大小,Q 是集合 X 的大小。
  • 你能给我一个链接或者可能是算法的名称吗?
  • 重要的不是算法,而是数据结构。正如您(和@amit)所提到的,如果您的可能元素数量有限,那么位集很有用。 hash table 是另一个非常有用的数据结构(在 C++ 中它被称为 unordered_map

标签: c++ algorithm set subset


【解决方案1】:

让我们暂时假设有 64 个可能的元素。

那么,如果将每个元素表示为一个位,则可以使用一个 64 位长的整数来表示每个集合,那么:a & b 就是abset intersection
如果(且仅当)ab 的子集,则 a & b == a

当然,如果您需要超过 64 位,您可以使用 bitset。

对于大范围的元素,可以使用哈希表存储(一次)超集,然后迭代潜在的子集以检查是否所有元素都在其中。
它在输入大小上是线性的(平均情况)。


编辑:(回复已编辑的问题)

除非你预先存储了一些关于数据的信息——否则O(|X| + n*min{m,|X|})无法做到|X|是集合 X 的大小,n 是集合的数量,m 是集合的平均大小。
这样做的原因是因为在最坏的情况下,您需要读取所有集合中的所有元素(因为您为每个集合读取的最后一个元素决定它是否是子集),因此如果没有先前的关于集合的知识。

建议的解决方案是:
位组:O(|X|*n)
哈希解:O(|X| + min{m,|X|}*n)(平均情况)

虽然散列解决方案提供了更好的渐近复杂度,但对于 bitset,常量要好得多,因此对于小的 |X|,bitset 解决方案可能会更快

【讨论】:

  • 你的答案是正确的。但是,如果集合中的集合数量很大但 X 中的元素数量很少怎么办?我可以更有效地做到这一点吗?
  • @Mohammad:编辑了答案。
【解决方案2】:

如果您没有时间限制构建一些额外的结构,O(log(n)) 的解决方案是将代表个体集的位序列存储在 Trie 中。

您不必像 Amit 所假设的那样将您的集合(也称为位串)与所有其他集合进行比较。如果您有一个排序的位串集合,那么每次比较显然会将变体的数量减少一半。是的,当然,构建 bitset trie 的时间大约是 O(n*log(n)),但它是一个预处理。

【讨论】:

  • 位串的排序集合如何将比较次数减少一半?例如如果 X={3,6} 并且 3 在其中一组中,那么 6 在没有 3 的情况下仍然可以在另一组中吗?我们如何在 Trie 中放置集合?如果我们想在 Trie 中搜索集合,时间复杂度很好。但是我们必须计算 X 和 Trie 中每个项目的交集。 Trie 如何帮助我们找到集合的交集?
猜你喜欢
  • 1970-01-01
  • 2017-01-01
  • 1970-01-01
  • 2018-06-22
  • 1970-01-01
  • 1970-01-01
  • 2021-09-14
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多