给定多个项目列表,找到包含匹配项目的列表。
此问题的强力伪代码如下所示:
foreach list L
foreach item I in list L
foreach list L2 such that L2 != L
for each item I2 in L2
if I == I2
return new 3-tuple(L, L2, I) //not important for the algorithm
我可以想到许多不同的方法 - 创建列表列表并在搜索其他候选列表后删除每个候选列表 - 但我想知道是否有更好的算法?
我正在使用Java,如果这对您的实现有所影响。
由于
答案 0 :(得分:5)
Map<Item,List<List>>.
现在,每个项目都有一个Map条目,告诉您该项目的列表。
此算法大约是 O(N),其中N是列表的数量(确切的复杂性将受到Map实现的好处的影响)。我相信你的算法至少 O(N ^ 2)。
警告:我正在比较比较次数,而不是内存使用情况。如果您的列表非常庞大并且大部分都是非重复的项目,那么我的方法创建的地图可能会变得太大。
答案 1 :(得分:2)
根据您的评论,您需要MultiMap实施。 multimap就像Map,但它可以将每个键映射到多个值。存储值和对包含该值的所有映射的引用。
Map<Object, List>
当然,您应该使用类型安全而不是Object
和类型安全List
作为值。您要做的事情称为Inverted Index。
答案 2 :(得分:1)
我首先假设数据集可以适合内存。如果没有,那么你需要更高级的东西。
我在下面引用一个“集合”,我想的是像C ++ std :: set这样的东西。我不知道Java等价物,但任何允许快速查找的存储方案(树,哈希表,等等)。
比较三个清单:L0,L1和L2。
<强>更新强> 刚刚意识到问题是“n”列表,而不是三个。但扩展应该是显而易见的。 (我希望)
更新2 一些未经测试的C ++代码来说明算法
#include <string>
#include <vector>
#include <set>
#include <cassert>
typedef std::vector<std::string> strlist_t;
strlist_t GetMatches(std::vector<strlist_t> vLists)
{
assert(vLists.size() > 1);
std::set<std::string> s0, s1;
std::set<std::string> *pOld = &s1;
std::set<std::string> *pNew = &s0;
// unconditionally load first list as "new"
s0.insert(vLists[0].begin(), vLists[0].end());
for (size_t i=1; i<vLists.size(); ++i)
{
//swap recently read "new" to "old" now for comparison with new list
std::swap(pOld, pNew);
pNew->clear();
// only keep new elements if they are matched in old list
for (size_t j=0; j<vLists[i].size(); ++j)
{
if (pOld->end() != pOld->find(vLists[i][j]))
{
// found match
pNew->insert(vLists[i][j]);
}
}
}
return strlist_t(pNew->begin(), pNew->end());
}
答案 3 :(得分:0)
您可以使用trie进行修改,以记录每个节点所属的列表。