【问题标题】:What algorithm to use to check if one set overlaps to another?使用什么算法来检查一组是否与另一组重叠?
【发布时间】:2015-02-23 06:20:26
【问题描述】:

我有很多组整数。我需要检查一个是否与另一个重叠(两组中至少存在一个相同的元素)。最好的方法是什么。我比较了两种方式:

HashSet<int> hs1, hs2;
hs1.Overlaps(hs2);

SortedSet<int> ss1, ss2;
ss1.Overlaps(ss2);

HashSet 更好,因为在这两种情况下,重叠都是可枚举的,并且在可枚举中进行扫描并在集合中查找。

但我觉得存在更好的算法来检查排序集中的重叠。

有谁知道算法,它允许使用两个集合都已排序的事实快速检查重叠?

UPD1 每组的大小约为 100-1000 个分布良好的整数。

【问题讨论】:

  • 如果您的序列已排序,您可以执行合并。这可能比构建哈希表要快。
  • @usr,构建集合的成本超出了范围。但无论如何构建哈希表通常比排序更快
  • 您关心的是绝对吞吐量还是渐近复杂度?
  • @usr,我的目标是提高性能,我想在真实数据上实现高平均吞吐量。
  • 您可以执行任何类型的预计算,例如排序、构建哈希表或其他事情吗?是否是小范围内的整数(例如 [1, 10000])?在这种情况下,您可以构建位图并使用二进制和相交。

标签: c# algorithm set hashset sortedset


【解决方案1】:

这在很大程度上取决于问题的大小(每组可能有几百到几万亿个条目)和输入的呈现方式(文件?适合内存?在多台机器上)。

一般来说,通过纯粹的比较,我们找不到比 O(n * log(n)) 更好的所有重叠集,其中“n”是自重复检测以来的元素总数(证明是 Omega(n * log (n)) 可以简化为这个问题。如果我们使用这个事实,可以根据问题的大小和数据集使用其他一些启发式方法:只有当端点重叠时,两个集合才能重叠,即,假设 A = {a1, ..., aN} 和 B = {b1, ..., bN}。如果 (aN

有了额外的内存(使用哈希/映射),你可以做得更好。考虑以下类比:假设您通过绘制最小和最大元素以及它们之间的数字来在数轴上绘制集合的“范围”。您需要知道的只是检查同一点是否被绘制了两次。以此为基础,这是一种可能的方法:(我不知道这个算法的 C# 等价物)

  1. 从 int -> {set name} 创建一个 hashmap M。所以如果一个元素 '5' 属于集合 '3',我们说 M[5] --> {3}。
  2. 循环遍历所有集合中的所有元素。
  3. 如果地图已存在,则当前循环的集合(例如 17)与地图中存在的设置值之间存在重叠。还将新集添加到 RHS。所以对于上面的元素,我们会看到 M[5] --> {3, 17}

上面的时间复杂度是 O(n * (cost of insert into set)) 。 (实际上是 n *(哈希查找的成本)*(插入集合的成本),但为了这个问题,我们可以假设哈希具有恒定的查找/插入时间)

插入集合的成本是 O(log(集合的大小))。在最坏的情况下,集合的大小可能是“n”,因为所有集合可能相互重叠。但是如果很多集合不太可能重叠,我们可以假设它的时间是恒定的,使得时间复杂度变成 O(n)。

请注意,上述解决方案没有使用集合本身已排序的事实,因为我们没有使用排序。

【讨论】:

  • 那么为什么是 -1 呢?评论会很有用。
  • @useruser1952500,感谢您的回答。我添加了有关集合属性的更多详细信息。我也将尝试减少计算次数的算法,并在此处添加结果。
【解决方案2】:

不可能比O(min(size of the first set, size of the second set)) 做得更好,因为在最坏的情况下,如果不查看其中至少一个集合的所有元素,就无法判断两个集合是否相交。

【讨论】:

  • 确实如此,但您可以获得更好的绝对吞吐量。
  • @usr 它需要一些关于集合的额外信息,这些信息在问题中不存在。
  • 如果我们处理有序集合,也许我们可以利用这个事实而不需要查看所有元素。这正是我的问题所在。
猜你喜欢
  • 1970-01-01
  • 2011-06-20
  • 1970-01-01
  • 2022-07-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多