如何计算该算法的运行时间?

时间:2013-07-07 16:58:28

标签: big-o

为了好玩,我写了一个字谜生成器。它需要一些输入单词或短语,并以不同的组合重新排列字母以生成新的单词或短语。例如,如果你输入了#cat; cat and dog",它会返回像#34;爸爸得到的东西等#34;或者" ant cog dad"。

一位朋友询问运行时间是什么,我意识到在这种情况下我不确定如何计算它。在启动时,我读了一个单词列表(一本字典)。就我而言,它大约有200,000个单词(它是标准的unix / usr / share / dict / web2字典)。这并不能真正影响到运行时间,因为它在应用启动时是一次性的事情,并且在读取和索引字典时需要一秒钟。

当用户输入单词时,应用程序在字典中搜索候选单词列表。如果单词仅包含输入单词或短语中的字母子集,则该单词是候选单词。生成候选人是这个过程中不可忽视的一部分,现在可以忽略。

然后开始搜索。它选择候选人名单中的第一个单词。接下来,它会从输入字符串中的其余字母中删除该字母的字母。然后,它搜索候选者以查找仅包含新减少的输入字符串的子集的剩余单词。然后使用新的缩减输入词和减少的候选列表进行递归。它会重复此操作,直到没有候选者,或输入字符串全部用完为止。

所以它可能从100个必须搜索的候选人开始。它选择一个,在删除任何其他字母后,可能会有90个,或者可能剩下50个,或者可能剩下10个,所以当我们递归时,每次都会留下不同的数字进行搜索。这就是我无法理解运行时间的原因。

如果我们从未删除列表中的任何单词,那么它将是O(n!),其中n是候选者的数量。但是,由于我们在每次迭代时都会严格修剪列表,因此它的效果远远低于n!。例如,我试过的一个短语产生了超过4,000个候选人,并最终找到超过600,000个组合。在最近的笔记本电脑上(仅使用一个核心)只需要大约30秒钟,所以很明显它不是O(n!)。

为了理解运行时间,我是否需要有一些关于每次迭代或类似情况下平均修剪候选人列表的统计数据?

我在想,如果每次迭代都从列表中删除了10个候选者,那么我们就会有100个候选列表:100 * 90 * 80 * 70 ...或者更一般地说,n *( n - 10)*(n - 20)*(n - 30)...在100个候选列表的情况下,可以计算出O(n ^ 10 - a * n ^ 9 - b * n ^ 8。 ..)。

我是否正确计算过,或者还有更多的计算?

3 个答案:

答案 0 :(得分:0)

你的方向正确。考虑您在评估时获得的唯一最高程度的多项式。所以在你的情况下:
n*(n-10)*(n-20)*...10

将提供(n)^(n/10)

因此,算法的运行时间为O( (n)^(n/10) )

另请参阅this以更好地了解运行时间。

答案 1 :(得分:0)

如果候选人的平均长度是k,并且源短语是所有候选者只被逐一删除,那么复杂性将是O((n / k)!)。

如果候选者的初始数量为M,并且每个步骤从候选者列表中删除s个单词,则复杂度为O(M *(Ms)*(M-2s)*。 ..)= O((M / s)!* s M / s )。

在最坏的情况下,你仍然有O(n!)。

但是,n!是人们对此类任务所期望的。我想大多数优化应该在搜索和删除候选者的代码上执行。

答案 2 :(得分:0)

首先,请注意,运行时间取决于输入的长度:O(m)。如果用户多次输入包含所有字母表字母的超长短语:

  

快速的棕色修复跳过懒狗;一个快速的棕色修复跳过懒狗;一个快速的棕色修复跳过懒狗,......

您的算法会在第一次n次迭代中考虑完整字典(大小为O(m)),因此运行时间为n^O(m)

在这里,语句n^O(m)相当弱,即使它是正确的:确切的运行时间可能看起来像n^0.01mn^0.1m;你可能会认为它们都小于n^O(m),但你找不到确切的因素(这取决于英语的结构),所以n^O(m)这里的意思是“在最坏的情况下指数运行时间;算法赢了没有完成m的大值。

当然,您可能对m的小值的运行时间感兴趣。如果你假设m<20,很明显运行时间是O(n ^ 20);您可以认为这是一个比O(n!)O(n^(n/10))更好的估算。

为了获得更好的估计,人们必须考虑字典的结构;运行时间在很大程度上取决于字典。例如,如果词典中的所有单词都包含至少2个字母(不确定),则可以将运行时间估计为O(n^(m/2))

无论如何,大O符号似乎并不适合这个问题。