我有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。并且没有平等集。
答案 0 :(得分:4)
我能想到的一个优化是记住第一组和其余部分之间的交叉点大小,然后使用数据来削减一些情况。
如何使用它:
如果您设置了A
,B
,C
长n
和
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
是每个集合中的元素数量:
val_map
O(X*Y)
counts
并将每个元素初始化为零是O(X^2)
O(X*Y)
中运行。但是,在另一个极端,如果有大量的交叉点(所有集合都是等价的),则最后一个循环在O(X^2*Y)
中运行。因此,根据交叉点的数量,时间复杂度介于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)
)。