在N列表中查找匹配项的有效方法?

时间:2010-07-09 15:48:23

标签: algorithm data-structures

给定多个项目列表,找到包含匹配项目的列表。

此问题的强力伪代码如下所示:

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,如果这对您的实现有所影响。

由于

4 个答案:

答案 0 :(得分:5)

  1. 创建Map<Item,List<List>>.
  2. 遍历每个列表中的每个项目。
  3. 每次触摸项目时,将当前列表添加到地图中该项目的条目。
  4. 现在,每个项目都有一个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。

  1. 读取L0,将每个元素放在一个集合中:S0。
  2. 读取L1,将与S0元素匹配的项目放入新的集合中:S1,并丢弃其他项目。
  3. 弃掉S0。
  4. 读取L2,保留与S1元素匹配并丢弃其他元素的项目。
  5. <强>更新 刚刚意识到问题是“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进行修改,以记录每个节点所属的列表。