生成排列的算法的复杂性

Posted

技术标签:

【中文标题】生成排列的算法的复杂性【英文标题】:Complexity of the algorithm that generates permutations 【发布时间】:2015-04-07 16:57:55 【问题描述】:

我很难理解如何确定该算法的时间复杂度(用 Python 编写,但适用于任何语言):

def permutazioni(list):
    n = len(list)
    if n == 1 or n == 0: 
        return [list]
    else:
        risult = []
        for i in range(n):
            primo = list[i]
            listaDegliAltri = list[:i] + list[i + 1:]  
            perms = permutazioni(listaDegliAltri)
            for perm in perms:
                risult.append([primo] + perm)
    return risult

此过程将一个序列作为输入,并作为结果返回一个序列序列,该序列包含起始序列的所有可能排列的集合。

例子:permutations([a, b, c]) = [[a, b, c], [a, c, b], [b, a, c], [b, c, a], [c, a , b], [c, b, a]]

现在,要确定复杂性,我必须编写并求解递推方程。 当列表长为 0 或 1 时,不进行任何操作。 否则,您将运行 n 次迭代循环,其中每次迭代都会在一个元素短于 (n-1) 的列表上调用函数,然后运行内部长n-1

教授接着写道:

T(0) = T(1) = 1(1为什么?是退货的成本还是其他?)

T(n) = n*(T(n-1) + (n-1)) 对于 n>1

然后他说选择下界然后写(以后什么都不懂):

T(n) > n*T(n-1)

来自:

T(n) > nT(n-1) > n(n-1)T(n-2) > n(n- 1)*(n-2)*T(n-3)> ... > n!

即:

T(n) = Ω(n!)

我不明白,因为它消除了 (n-1) 并且因为它使用了大调而不是等号。所以我什么都不懂。 有人给我解释一下就知道了? 谢谢

【问题讨论】:

【参考方案1】:

这只是很多容易出错但非常基本的代数。

M(1) 和 M(0) 为 1 的原因是因为如果您有一个包含 1 个或零个元素的列表,那么该列表本身就是它的唯一排列。例如1 只有一个排列, 也是如此。所以 1 本身与所做的工作无关,但实际上只有一个排列。但也确实,你只是简单地返回它,所以你可以这样想。

现在是更有趣/无聊的部分。

如果你接受

T(0) = T(1) = 1

T(n) = n*(T(n-1) + (n-1)) 对于 n>1

剩下的就是繁琐的代数了。所以首先说 T(n-1)=T(k)。所以

T(n) = n*((k*(T(k-1) + (k-1))) + (n-1))

T(n) = n*(((n-1)*(T(n-1-1) + (n-1-1))) + (n-1))

T(n) = n*((k*(T(n-2) + (n-2))) + (n-1))

T(n) = n^3 + n^2*T(n-2) - 2n^2-n*T(n-2)+n:这只是代数展开.

如果你替换T(n-2),然后用T(k)替换T(n-3),你会看到阶乘模式出现,即n! = n*(n-1)!

【讨论】:

【参考方案2】:

您的教授可能应该写成 T(0) = T(1) = Theta(1),这意味着在这些情况下它需要恒定的时间,但是仅仅放置一个像 1 这样的固定常数通常不会改变渐近线。至于其他的,如果你相信的话

T(n) = n*(T(n-1) + Theta(n-1)) 

(我再次使用 big-Theta 来强调在计算操作时可能存在隐藏的常数乘数),那么您显然明白了

T(n) > n*T(n-1)

因为你减去了正项 Theta(n-1)。其余的遵循阶乘的定义。

【讨论】:

以上是关于生成排列的算法的复杂性的主要内容,如果未能解决你的问题,请参考以下文章

这种寻找排列的回溯算法的时间复杂度是多少?

堆的算法时间复杂度

堆的算法时间复杂度

算法小计-列表排列

哈密 顿路径算法时间复杂度

[翻译]基于词典序的生成下一排列算法