随机选择两个集合,两个集合都包含不同的密钥(一个密钥可能属于多个集合,一个集合永远不能包含重复的密钥)。
返回一个整数,表示属于两个组的键数。
例如,intersect({1,2,3,4},{3,4,5})返回2。
我只需要交叉点的大小。我不需要确切知道交叉点中哪些键。
是否有任何数据结构支持小于O(n)时间的此类操作?
编辑:
读取数据确实需要O(n)时间,但不会导致您不能在O(n)时间内完成交叉操作的结论。
想象一下这个场景:
我有N套,每套包含100把钥匙。我读了它们,那是N * 100次操作。现在我想知道女巫对有最大的交集,即O(N²)交叉操作。所以我想减少交叉操作的复杂性。我不是真的关心读取和构建集合需要多少时间,最多N * 100,这与O(N²)交叉操作无关。
请注意,你不可能通过少于O(N²)交叉操作找到具有最大交叉点的那对集合,我可以证明这一点。你必须做所有交叉口作业。
(他的基本思想是,让我们想象一个完整的图,有N个顶点,每个顶点代表一个集合,Nx(N-1)/ 2个边,每个代表连接对的交集。现在给出每个边你想要的非negetive重量(代表交叉点大小),我总是可以构造N个满足那些Nx(N-1)/ 2边缘权重。这证明了我的主张。)
答案 0 :(得分:7)
我建议你看看两种可能的替代方案,这些方案在实践中特别有效(特别是在大型集合的情况下)。
布隆过滤器是一种节省空间的(基于位阵列)概率数据结构,用于测试元素是否是集合的成员。假阳性匹配是可能的,但假阴性不是。
假阳性率与布隆过滤器的内存占用之间存在折衷。因此,可以针对不同的用例估计布隆过滤器的适当大小。
每个集合都可以与自己的Bloom过滤器相关联。 很容易获得布隆过滤器,它对应于不同集合的交集:所有位数组(对应于不同的布隆过滤器)可以使用按位AND
进行组合操作
使用与交叉点对应的布隆过滤器,可以快速找到所有交叉集合中存在的项目。
除此之外,可以在没有实际迭代的情况下估算交叉点的基数: https://en.wikipedia.org/wiki/Bloom_filter#The_union_and_intersection_of_sets
跳过列表是一种数据结构,允许在有序的元素序列中进行快速搜索和交叉。通过维护链接的子序列层次结构,可以实现快速搜索和交叉,每个子序列跳过更少的元素。
简洁地说,Skip List与普通的Linked List数据结构非常相似,但是Skip List的每个节点都有一些额外的指向项目的指针,这些指针位于更远的位置(指针,“跳过”这对夫妇列表的其他节点)。
因此,为了获得交集 - 需要将指针保持在所有正在相交的跳过列表中。在跳过列表的交集期间,指针跳过项目,这些项目不存在于所有相交的跳过列表中。因此,通常交叉操作的运行时复杂性比O(N)
快。
“信息检索简介”(由Christopher D. Manning,Prabhakar Raghavan,HinrichSchütze编写)一书中描述了Skip Lists交集的算法: http://nlp.stanford.edu/IR-book/html/htmledition/faster-postings-list-intersection-via-skip-pointers-1.html
跳过列表主动用于高性能,功能齐全的文本搜索引擎库:Apache Lucene(在反向索引组件中使用跳过列表)。
以下是有关Lucene中跳过列表用法的其他Stackoverflow问题:how lucene use skip list in inverted index?
答案 1 :(得分:1)
假设有一种算法允许在不到O(n)
时间内检查交叉口长度。现在让我们阅读部分输入内容。我们有两种选择:
我们已经阅读了整套和另一部分,或者我们已经阅读了第一部分和另一部分。
选项1):
反例 - 让我们进行这样的输入,即存在一个在第1组中读取但尚未从第2组中读取的元素,但它在第2组中 - 我们将收到结果不正确。
选项2):
反例 - 我们可以输入这样的元素,它存在两组,但至少没有被读过。我们收到的结果不正确。
好的,我们已经证明,当我们不读取整个输入时,没有这样的算法可以返回正确的结果。
让我们读取整个输入 - n
数字。哎呀,复杂性是 O(n)。
结束证明。