我的迭代DP解决方案如下:
def permutations(string):
# let n = len(string)
N = [[] for _ in range(len(string) + 1)] # O(n)
N[0].append("")
for i in range(1, len(string) + 1): # O(n)
N[i] = [perm[:j] + string[i - 1] + perm[j:] for j in range(i) for perm in N[i - 1]] # O(???)
return N[-1]
但是,我无法分析上述程序的运行时间。具体来说,限制行for perm in N[i - 1]
的运行时。我知道递归解决方案是O(n!)
,但是如何在不依赖于知道递归运行时的情况下找到上述程序的运行时?
答案 0 :(得分:0)
让我们考虑一下
N[i] = [perm[:j] + string[i - 1] + perm[j:] for j in range(i) for perm in N[i - 1]]
是我们的主要兴趣。
我们可以将其重写为
line 1: for i in range(1, len(string) + 1): # O(n)
line 2: N[i] = [] # O(n)
line 3: for j in range(i): # O(sum i from 1 to n)
line 4: for perm in N[i - 1]: # O(sum len(Ni) from 1 to n)
line 5: N[i].append(perm[:j] + string[i - 1] + perm[j:])
现在,对于i = 1
,line 3
和line 4
会一次运行,N[1]
只有一个元素string[0]
。
对于i = 2
,line 3
将运行两次,line 4
将在第一次运行时运行一次,为第二次运行运行2次,而N[2]
将包含三个元素。< / p>
看到模式?让我们快进吧。 6,24,120,720。
N total runs diff
1 1 1
2 3 2
3 9 6
4 33 24
5 153 120
...
因此我们得到了
的完全复杂性 n
____
\
> k!
/___
k = 0 (asciiart courtesy of sympy)
简化它非常复杂(https://math.stackexchange.com/questions/227551/),但我们可以确保它在O(n!)
边界内,因为k*k!
从1到n的总和是(n+1)! - 1
,所以我们得到的总运行时间为O(n!)
,,而不依赖于已知的递归运行时。