n个集合之间的最大交集

时间:2015-11-05 15:44:33

标签: algorithm set

我有x个集合,每个元素都有y个元素(未排序的整数)。我想找到这组之间的最大交叉大小。

例如:

  

* 5套,尺寸= 3

     

设置1:1 2 3

     

设置2:4 2 3

     

设置3:5 6 7

     

设置4:5 8 9

     

设置5:5 10 11

最大交点已设置1与集合2,它的大小为2; 答案是2。

所以,我可以使用HashSets在O(x ^ 2 * y)中进行,只需查看所有对并计算它们的交集大小。但我想更快地做到这一点。我认为有特定的算法或数据结构可以提供帮助。你能给我一些想法吗?

UPDATE :x和y约为10 ^ 3,元素为int。并且没有平等集。

3 个答案:

答案 0 :(得分:4)

我能想到的一个优化是记住第一组和其余部分之间的交叉点大小,然后使用数据来削减一些情况。

如何使用它:

如果您设置了ABCn

intersection(A,B) = p
intersection(A,C) = q

然后

intersection(B,C) <= n - abs(p - q)

对于您的案例中的集合:

S0 = { 1 2 3 }
S1 = { 4 2 3 }
S2 = { 5 6 7 }

你计算intersection(S0,S1) = 2并记住结果:

[ i(0,1)=2 ]

然后intersection(S0,S2) = 0,所以

[ i(0,1)=2; i(0,2)=0 ]

在比较第一个元素后计算intersection(S1,S2)

(S1[0]=4 != S2[0]=5)

你可以说intersection(S1,S2) <= 2这是你迄今为止最好的结果。

可以进一步改进的是记住交叉点的更精确结果,但仍然没有计算所有交叉点。

我不确定这是不是最好的选择。也许存在完全不同的方法。

答案 1 :(得分:4)

这是一些伪代码:

function max_intersection(vector<vector<int>> sets):
    hashmap<int, vector<set_id>> val_map;
    foreach set_id:set in sets:
        foreach val in set:
            val_map[val].push_back(set_id);
    max_count = 0
    vector<int> counts = vector<int>(size = sets.size() * sets.size(), init_value = 0);
    foreach val:set_ids in val_map:
        foreach id_1:set_id_1 in set_ids:
            foreach id_2:set_id_2 in set_ids where id_2 > id_1:
                count = ++counts[set_id_1 * sets.size() + set_id_2];
                if (count > max_count):
                    max_count = count;
    return max_count;

因此,如果X是集合数,Y是每个集合中的元素数量:

  1. 插入val_map O(X*Y)
  2. 创建counts并将每个元素初始化为零是O(X^2)
  3. 如果没有交叉点(每个值恰好出现一次),则最后一个循环在时间O(X*Y)中运行。但是,在另一个极端,如果有大量的交叉点(所有集合都是等价的),则最后一个循环在O(X^2*Y)中运行。
  4. 因此,根据交叉点的数量,时间复杂度介于O(X*Y + X^2)O(X^2*Y)之间。

答案 2 :(得分:2)

我无法想出能够改善O(x*x*y)的解决方案,但我可以建议一种避免散列的方法,而不是预期的复杂性 O(x*x*y),以便具有复杂性{{ 1}}以10 ^ 6额外内存为代价。查看您提供的限制,您将拥有不超过10 ^ 6个不同的数字。所以我的想法如下 - 对所有数字进行排序,然后将它们唯一(删除重复数据)。为每个数字分配1到10 ^ 6(或唯一数字的数量)的唯一编号(使用它们在已排序和未组合数组中的顺序)。之后,而不是每对的hashmap,使用大小为10 ^ 6的位集。这样,您将具有O(x*x*y)的特定复杂度(因为我建议的预计算具有复杂性O(x*x*y))。