在解释recursive algorithms to generate permutations in lexicographic order时,我提供了一个简单的算法:
def permute(done, remaining):
if not remaining:
print done
return
sorted_rem = sorted(remaining)
l = len(sorted_rem)
for i in xrange(0, l):
c = sorted_rem[i]
# Move to c to done portion.
done.append(c)
remaining.remove(c)
# Permute the remaining
permute(done, remaining)
# Put c back.
remaining.append(c)
# Remove from done.
del done[-1]
def main():
permute([], [1,2,3,4])
if __name__ == "__main__":
main()
First question: It seems a bit wasteful to me and I wonder what the time complexity it really has, given a pythonic implementation like this?
注意,最佳的时间复杂度是O(n * n!)
,因为我们需要打印n!大小为n的排列
我猜测是因为排序(在python中我假设是O(n log n)
),一个额外的log n
因子将被添加(对于我们可以使用这个程序的n
来说,这个因子几乎可以忽略不计)。在
问题的第二部分是对它进行一点优化。在
Second question: Assuming that we can implement
sorted
inO(n)
time, andappend
,remove
anddel[-1]
inO(1)
time, what would be the resulting time complexity?
我相信有证据表明运行时确实是
O(n*n!)
。在(灵感来自前面的一个问题:complexity of recursive string permutation function)
对于所花费的时间,我们有以下递归,无需打印:
T(n) = n*T(n-1) + O(n^2)
现在如果
U(n) = T(n)/n!
那么我们必须得到它U(n) = U(n-1) + O(n^2/n!)
这是一个伸缩系列。在
因此我们得到
U(n) = U(1) + 2^2/2! + 3^2/3! + ... + n^2/n!
使用
e^x
的幂级数,乘以x几次微分,我们看到2^2/2! + 3^2/3! + ... + n^2/n! = O(1)
因此
T(n) = O(n!)
。在这是没有印刷的时间。在
因此,打印的总时间是
O(n * n!)
。在这也证明了
sorted
等的运行时间是多少并不重要,只要它们是多项式的,该算法都是渐近最优的。在常数可能是错误的,这正是处理
n*n!
时的实际问题。在我不知道什么是“python”式的方法,但我认为将一个序列(以数组形式给出)转换为下一个字典排列可能比递归构造它更容易(尤其是在集合和排序中有多个删除)。下一个排列可以在线性时间中找到,如下所示:
下面是五个例子的过程的简单可视化。该条指示后缀位置。在
优点:
print(done)
替换为任何其他use(done)
相关问题 更多 >
编程相关推荐