我编写了这段代码,返回了所提供字符串的所有排列。现在,我想计算运行时的复杂度,并需要帮助。
代码N次递归调用permutationRecursively
函数(对于字符串的每个字符,即st),然后有两个for循环,一个循环遍历所有从递归调用返回的排列(例如,{ {1}}将是['a']或a
将是['ab','ba']等),然后是每对排列。我对这部分真的很困惑。这个特定部分的复杂性是什么?
我假设对于所有递归调用,它将为ab
,然后对于内部循环,它将为O(N)
。因此总数为O(A*B)
。正确吗?
O(N*A*B)
答案 0 :(得分:1)
您的函数首先在大小为 n-1
的输入上递归调用自身。然后它循环遍历结果的每个元素(其中有 (n-1)!
),并且对于每个元素,它执行 O(n²)
工作(因为 len(permutationPair)+1
的长度为 n
并且字符串连接是 O(n)
。
因此我们得到以下时间复杂度T(n)
的递推关系:
T(n) = T(n-1) + (n-1)! n²
这个关系的渐近行为如下:
T(n) ∈ Θ((n-1)! n²) = Θ(n!n)
所以,特别是 T(n) ∉ O(n!)
。
答案 1 :(得分:0)
对于这样的问题,我发现简单地计算最内部循环的迭代次数将使您对复杂性有一个很好的了解。
count = 0
.
.
.
for index in range(len(permutationPair)+1):
global count
count += 1
newPermutations.append(permutationPair[0:index]+wordToInsert+permutationPair[index:])
通过此修改,我们有了一个不同输入的计数表:
从最后一个条目开始,我们减去前面的条目。这给出了:
鉴于我们正在处理排列,上面的数字应该很熟悉。很简单,它们是每个输入长度的阶乘。
因此,复杂性类似于:
O(n! + (n - 1)! + ... + 2!)
也许这可以简化为总和1到n。 WolframAlpha对此的评价如下:
赞!那不容易消费。我的直觉是,随着n的增加,第一项将占主导地位。请记住,我们正在处理渐近行为,因此我们只关心n变大时发生的情况。
让我们通过查看factorail(n) / sum([factorial(x) for x in range(2, n + 1)])
from math import factorial
def get_ratio(n):
return factorial(n) / sum([factorial(x) for x in range(2, n + 1)])
[get_ratio(x) for x in range(2, 30)]
[1.0, 0.75, 0.75, 0.7894736842105263, 0.8256880733944955, 0.8525033829499323,
0.8721232047066967, 0.8869942705176088, 0.8986822892623713, 0.9081347182982339,
0.9159495525890125, 0.9225247281105151, 0.9281368938946185, 0.932985094435074,
0.9372165386007432, 0.9409426073299031, 0.9442492142738237, 0.947203738596165,
0.9498597948796416, 0.9522605938189509, 0.9544413593967874, 0.9564310992723437,
0.9582539225228436, 0.9599300347361424, 0.9614764993074284, 0.9629078267955898,
0.9642364361184396, 0.9654730190404553]
随着n的增加,我们发现表达式的大部分来自我们怀疑的第一项。
因此,最终,您的算法的复杂度(我可能会添加一点也不奇怪)是
O(n!)