Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/10.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
String 将算法的大O表示法从O(n^2)改进为更好的形式_String_Algorithm_Time Complexity_Big O - Fatal编程技术网

String 将算法的大O表示法从O(n^2)改进为更好的形式

String 将算法的大O表示法从O(n^2)改进为更好的形式,string,algorithm,time-complexity,big-o,String,Algorithm,Time Complexity,Big O,我希望改进我目前拥有的一个算法,虽然它有效,但目前的复杂度为O(n^2)。如果可能的话,我希望降低复杂性,或者改进/更改算法本身,以提高运行时间 我有一个字符串列表,每个字符串包含多个单词,最终目标是在这些字符串之间找到“匹配项”,根据“相似性”百分比排序 假设我有以下字符串: “世界末日” “旅程的开始” “时间的终结” “我们今天离开这个世界的时间” 我的算法执行以下步骤: 遍历每个字符串,将每个字符串分解为其组成词,并按字母顺序对这些词重新排序(整个算法不区分大小写)。 (也就是说,“世

我希望改进我目前拥有的一个算法,虽然它有效,但目前的复杂度为O(n^2)。如果可能的话,我希望降低复杂性,或者改进/更改算法本身,以提高运行时间

我有一个字符串列表,每个字符串包含多个单词,最终目标是在这些字符串之间找到“匹配项”,根据“相似性”百分比排序

假设我有以下字符串:

“世界末日”
“旅程的开始”
“时间的终结”
“我们今天离开这个世界的时间”

我的算法执行以下步骤:

  • 遍历每个字符串,将每个字符串分解为其组成词,并按字母顺序对这些词重新排序(整个算法不区分大小写)。 (也就是说,“世界末日”变成了“世界末日”,“我们今天离开这个世界的时候”变成了“今天离开这个世界的时候”等等)
  • 出于业务原因,某些单词会从处理过的字符串中删除。这通常是代词和其他类似的词,例如a、the等,所以“世界末日”变成了“世界末日”
  • 我们现在有了一个字符串列表,这些字符串被打断,并按照字母顺序从它们的组成词中重新组合,删除了特定的非基本词
  • 首先,我可以简单地看看列表中是否有完全相同的副本。这很简单,允许我识别那些实际上是100%匹配的字符串
  • 然而,现在是算法中最难和最慢的部分。我必须遍历字符串列表,将每个字符串与列表中的每个其他字符串(即嵌套循环)进行比较,以确定每个字符串在两个被比较字符串中有多少个共同的单词。i、 当比较“世界末日”和“时间末日”时,有66.6%的共性,因为两个字符串有三分之二的共同词。当比较“世界末日”和“Left This Time Today We World”时,我们发现两个字符串之间只有一个单词是相同的(因为每个字符串中的单词数不同,本例中的实际百分比是基于两个字符串之间的平均值计算的,因此大约有22%的共性)
最后,我只剩下一对字符串(开始列表中所有字符串的每一个可能的配对)和它们之间匹配的百分比值。然后,我可以放弃低于某个阈值的所有匹配,只处理高于阈值的匹配。阈值是用户定义的,整个算法可以作为“过滤”一组非常大的数据的一种方式,允许人类的眼球只处理那些一开始看起来非常匹配的数据片段

正如您可以从算法的嵌套循环(即O(n^2))部分想象的那样,这非常慢,并且随着输入大小的增加而变得相当慢


是否有任何方法可以改进该算法的大O,或者对该算法进行任何更改,以产生相同的输出,从而提高运行时的复杂性?

如果在所有计算中都使用字符串,则会增加额外的复杂性,这使得最后一个操作不是O(M^2),而是O(M^2*sizeof)(句子)*AvgLength(单词))

让我们看看(概念代码)

这里的总数是O(sSet.size()^2*O(set.size())。 可以优化为仅运行O(sSet.size()*sSet.size()/2),因为表是对称的

使用
查找
在此处保存因子O(字号)


std::集合可能会被一些平面集合所取代,以实现更快的实际操作。

该算法的第一部分的顺序为O(n^2)还有,如果你有N个单词和N行要扫描overNo,就必须将每个句子放入数据结构(如二叉树)中。顺便说一句,你删除的琐碎单词通常称为停止词。通常(但不总是…)在这种情况下,单词越稀罕,就越应该重视一个事实,即它恰好由一对标题共享。在这种情况下,它可以帮助扭转局面,为每个单词记录包含该单词的标题集。然后为每个单词(从出现在最少标题中的单词开始),为每对具有该单词的标题添加一个权重(您可以将这些标题存储在哈希表中)。一旦标题计数开始变得太大,请停止。@meat说整件事是
O(n^2)
对我来说没有多大意义。它是
O(M*n*n)
,大致上,其中
M
是句子的数量,
N
是每个句子中的平均词条数量。但是,正如下文所述,OP已经可以将其归结为
O(M*N*lgN)
。如果
M
是句子的数量,检查所有句子对就是
O(M^2)
操作。我忽略了一个事实,
N
在这里指的是术语,而不是句子。
std::vector<std::set<int>> sSets;
sentenceSets.reserve(sentences.size());

for(auto& sentence : sentences) { // O(m)
  std::vector<const char *> words = SplitWord(sentence); // O(n) needs to go through all letters.
  sSet.emplace_back();
  for(auto& word: words) {
    int wordNo = LookUp(word); // table of all words, with entries of 0 for unwanted words. O(log AllWords)
    if (wordNo)
      sSet.back().insert(wordNo); // also removes duplicates. O(Log(#diff words in sentence))
  }
} 
for(const auto& theSet : sSet) { // O(sSet.size()
  for(const auto& cmpSet : sSet) { // O(sSet.size()
    std::vector<int> intersect;
    std::set_intersection(theSet.begin(), theSet.end(),
                          cmpSet.begin(), cmpSet.end(),
                          std::back_insert<std::vector<int>>(intersect)); // O(set.size())
    StoreRes(theSet, cmpSet, intersect);
  }
}