Algorithm 查找集合对,使其并集具有特定大小
我有一个变量,如下所示:Algorithm 查找集合对,使其并集具有特定大小,algorithm,scala,optimization,set,knapsack-problem,Algorithm,Scala,Optimization,Set,Knapsack Problem,我有一个变量,如下所示: var L_s = collection.mutable.Set[collection.mutable.Set[Int]]() 我想找到不同大小集合的并集 请注意:当我们想要找到大小为k的并集时,L_中的所有集合的大小都将与k-1相同 截至目前,我正在做以下工作: for(i <- L_s){ for (j <- L_s){ if((i.union(j)).size == k) { res.+=(i.union(
var L_s = collection.mutable.Set[collection.mutable.Set[Int]]()
我想找到不同大小集合的并集
请注意:当我们想要找到大小为k的并集时,L_中的所有集合的大小都将与k-1相同
截至目前,我正在做以下工作:
for(i <- L_s){
for (j <- L_s){
if((i.union(j)).size == k)
{
res.+=(i.union(j))
}
}
}
for(i由于union
是可交换的(a union b==b union a
),您所做的操作是所需操作的两倍,并且在找到目标大小时再次重复union
操作,并且每个集合本身都会得到union
。这些低效可以消除
L_s.toVector.combinations(2).map(x => x(0) union x(1)).filter(_.size == k).toSet
基本上有两种加速算法的机会:
加速两组的单个比较
减少所需比较的总数
比较的意思是检查两个集合的并集是否有sizek
第一个是比较简单的部分,我在前面的回答中提到过。你不必实际计算并集并检查它的大小。只需知道交集的大小(不是实际的交集,只是它的大小)就足够了。遍历第一个集合的元素并计算第二个集合中出现的元素(非常高效的查找)。如果交叉口的大小k-2
您发现一对集合符合您的要求。当您发现两个元素不在第二个集合中时,您应该中断循环,因为从此处您将永远无法达到交叉口大小k-2
这是因为两个具有required属性的集合除了每个集合中的一个元素外,所有元素都是相同的。这意味着集合1正好有一个元素不在集合2中,反之亦然
你也可以利用这个属性来限制比较的数量。这个想法如下:你的集合包含可以排序的整数。如果一对集合有资格,并且你只考虑每个集合中最低的两个整数,我们把它称为前缀,前缀至少有一个共同的整数。任何其他都会是矛盾的。符合你的要求
现在,您可以提前按其最低和第二低整数对所有集合进行索引。即,您构建两个类型为Map[Int,Set[Set[Int]]的映射
,让我们将它们称为setsByLowestMember
和setsbysecondlowstmember
。当您现在循环所有集合进行测试时,而不是针对每一个其他集合测试一个集合,您只测试那些最低或第二最低成员等于当前集合中最低或第二最低成员的集合
示例:正在考虑的当前(已排序)集合是{3,7,9,…}
。您可以检查所有setsByLowestMember(3)
,setsByLowestMember(7)
,setbysecondlowsmember(3)
和setbysecondlowsmember(7)
根据您的数据,这可能会显著加快您的算法。但是,如果您的集合通常具有非常大的交集,则可能没有多大帮助。如果有帮助,则可以进一步改进(仍有一些检查使用上述方法进行了两次).此解决方案正在获取结果。但是时间几乎相同。我可能必须优化代码的其他部分。我正在尝试查找频繁项集。我将找到一种方法来减少L_s变量中的集合数。这可能有助于加快代码的速度。的确,工作量与L_s
的大小成二次关系。总之我们是否还应该了解集合的其他特征?集合的元素是否已知,即相对于k
,总共有多少不同的元素?理论上是否可能所有集合都有不同的元素,即它们是共同的完全不相交?不,我提到的唯一一件事是,当我们想找到大小为k的并集时,L_s中的所有集合的大小都将与k-1相同。因此,如果我可以删除我发布的方法所做的任何冗余计算,将有助于加快我的算法。我目前正在处理的问题会生成许多集合。我正在尝试降低在数量上。我认为数量是缓慢的根本原因。