我有多个变长ArrayList,需要找到它们的交集。字符串集合数量的实际上限可能在35左右但也可能更多。我不需要任何代码,只是想听听其他高效解决思路。
目前来看,我的解决方案看起来具有渐进运行时间为Θ(n2)的特点。
感谢任何帮助!
tshred
编辑:为了澄清,我真正想知道的是是否有更快的方法。比Θ(n2)更快的方法。
我有多个变长ArrayList,需要找到它们的交集。字符串集合数量的实际上限可能在35左右但也可能更多。我不需要任何代码,只是想听听其他高效解决思路。
目前来看,我的解决方案看起来具有渐进运行时间为Θ(n2)的特点。
感谢任何帮助!
tshred
编辑:为了澄清,我真正想知道的是是否有更快的方法。比Θ(n2)更快的方法。
Set.retainAll()
是查找两个集合的交集的方法,如果你使用HashSet
,那么将你的ArrayList
转换为Set
并在循环中使用retainAll()
实际上是O(n)的。
接受的答案已经很好了;更新一下:自从Java 8之后,有一种稍微更有效的方法来查找两个Set
的交集。
Set<String> intersection = set1.stream()
.filter(set2::contains)
.collect(Collectors.toSet());
稍微更高效的原因是,原始方法必须将set1
的元素添加到结果集中,如果它们不在set2
中,则必须再次将其删除。这种做法仅向结果集中添加需要在其中的内容。
严格来说,在Java 8之前也可以这样做,但是没有Stream
,代码会更加费力。
如果两个集合大小差别很大,则应优先选择较小的集合进行流处理。
.collect(Collectors.toSet())
更改为 .forEach(e -> ...)
将是找到两个集合交集的理想方式,而不会创建任何一个集合的副本或对交集的引用。换句话说,如果 a = { 1, 2, 3 }
和 b = { 4, 5, 6 }
并且调用了 forEach(e -> ...)
,那么在任何时候只会存在七个元素引用。三个来自集合 a
,三个来自集合 b
,一个来自回调变量 e
。 - Hatefiendset1
或 set2
中哪个元素数量最少,然后将该集合作为流式处理的集合。剩余的集合将被引用为 contains
。 - Hatefiend此外,Google Guava 中还有一个静态方法 Sets.intersection(set1, set2)
,它返回两个集合交集的不可修改视图。
if (intersetionSet.size() < 1000) { doSomethingWith(intersetionSet); }
- Annan Yearian还有一个想法——如果你的数组/集合大小不同,那么从最小的开始是有意义的。
最好的选择是使用HashSet来存储这些列表的内容,而不是使用ArrayList。如果你能这样做,你可以创建一个临时的HashSet,将要交集的元素添加到其中(使用putAll(..)方法)。然后执行tempSet.retainAll(storedSet),tempSet将包含交集。
你可以使用单个 HashSet。当对象已经在集合中时,它的 add() 方法返回 false。从列表中添加对象并标记 false 返回值的次数将为您提供集合的并集和直方图数据(并且计数+1等于列表计数的对象是您的交集)。如果您将计数抛到 TreeSet 中,您可以尽早检测到空交集。
set1.stream().anyMatch(set2::contains)