高效的列表交集算法

83

给定两个列表(不一定排序),最有效的非递归算法是什么,用于查找这些列表的交集?
我不认为我可以访问哈希算法。


3
这听起来像一道作业问题 - 是吗? - Erik Forbes
34
实际上不行。我在工作中,需要在一个名为eviews的统计建模环境中进行编程。Eviews没有内置集合交集功能,并且也不支持递归。我需要一个快速算法,因为我的集合往往很大,程序需要经常运行。谢谢! - David
4
每个列表中的数值都是唯一的吗?如果是,你可以将这些列表合并,对结果进行排序,然后查找重复项。 - Fabio Ceconello
1
通常集合中有多少个元素?(例如,是否值得尝试实现哈希,还是可以通过排序来解决 = O(nlogn)?) - Jason S
2
你要排序的数据类型是什么?有时候,数据的特性可以在设计算法时加以利用。 - AShelly
显示剩余3条评论
15个回答

1

为什么不自己实现一个简单的哈希表或哈希集?如果你的列表很大,避免nlogn交集是值得的。

由于你事先对数据有一定了解,应该能够选择一个好的哈希函数。


1

如果支持集合(如标题中所称)作为内置,则通常会有一个交集方法。

无论如何,正如某人所说,如果您已经对列表进行了排序,那么可以很容易地完成它(我不会发布代码,因为已经有人这样做了)。 如果您不能使用递归,则没有问题。 有快速排序非递归实现。


  1. 如果Eviews支持集合,它可能会提供一种集合交集的方法。
  2. 如何将两个集合合并有助于这里。交集是两个集合中都存在的元素。当我听到“合并”时,我想计算两个集合的并集。
- f3lix
Java 支持集合,但没有内置的交集函数。 - lensovet
2
@lensovet:如果它实现了java.util.Set接口,那么就可以使用java.util.Set.retainAll(Collection)方法。它的文档描述如下:“如果指定的集合也是一个set,则此操作会有效地修改此set,使其值为两个集合的交集。” - Andrea Ambu

0

时间复杂度: O(n) 空间复杂度: O(1) 用于识别交点的解决方案。

例如,通过在每次到达末尾时交换指针,这两个给定节点将检测到交点。 视频解释在此处。

public ListNode getIntersectionNode(ListNode headA, ListNode headB) {
    ListNode pA = headA;
    ListNode pB = headB;
    while (pA != pB) {
        pA = pA == null ? headB : pA.next;
        pB = pB == null ? headA : pB.next;
    }
    return pA;
}

谢谢。

编辑

我对交集的理解是找到交点

例如:

Intersection

对于给定的列表 A 和 B,A 和 B 将在点 c1 "相遇/交叉",上述算法将返回 c1。正如 OP 所述,OP 没有访问哈希映射或某种类型,我相信 OP 是说该算法应具有 O(1) 空间复杂度。
我是从 Leetcode 上获得这个想法的,如果您感兴趣:两个链表的交点

从David对其他答案的评论来看,他似乎正在寻找两个列表中共同的所有元素。您能否在帖子中总结视频的信息,特别是使用的“交集”解释? - greybeard
@老程序员,没问题,我已经编辑了我的答案以满足您的需求。如果有任何不清楚的地方,请告诉我。谢谢。 - minchaej

0

根据Big-Oh符号的定义:

如果存在正常数c和n 0 ,使得N ≥ n 0 时 T(N) ≤ cf(N),则 T(N) = O(f(N))。

实际意义是,如果两个列表的大小相对较小,例如每个列表不超过100个元素,则使用两个for循环可以很好地解决问题。循环第一个列表并在第二个列表中查找相似的对象。在我的情况下,它可以很好地工作,因为我的列表中不会有超过10-20个元素。但是,一个好的解决方案是对第一个列表进行排序O(n log n),对第二个列表也进行排序O(n log n),然后将它们合并,大约需要O(n log n)的时间,粗略地说是O(3n log n),假设两个列表的大小相同。


0

在PHP中,类似于

function intersect($X) { // X is an array of arrays; returns intersection of all the arrays
  $counts = Array(); $result = Array();
  foreach ($X AS $x) {
    foreach ($x AS $y) { $counts[$y]++; }
  }
  foreach ($counts AS $x => $count) {
    if ($count == count($X)) { $result[] = $x; }
  }
  return $result;
}

1
如果您在任何数组中有重复项,将会导致不正确的行为。 - Slawek

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接