排列算法分析:递归排列算法的时间复杂度是否为O(n!)?
递归排列算法疑问解答:代码逻辑 + 时间复杂度分析
嘿,先别被递归搞疯!咱们一步步拆解你代码里的疑问,再聊聊时间复杂度的问题~
先解释你代码里的两个疑问
首先把你的代码格式化一下,方便咱们看:
def permute(s): out = [] if len(s) == 1: # wouldn't setting out replace everything in out? out = [s] else: for i, let in enumerate(s): # how does it know that I only want 2 strings? for perm in permute(s[:i] + s[i+1:]): out += [let + perm] return out print(permute("cat"))
疑问1:# wouldn't setting out replace everything in out?
完全不用担心“替换掉之前的out”!这里的out是函数的局部变量,每次递归调用permute都会在新的函数栈帧里创建一个全新的out,和上层递归的out完全没关系。
当len(s) == 1时,这是递归的基准情况——单个字符的排列只能是它自己,所以把out设为[s]是完全合理的。这个值会返回给上层递归,上层会用它来拼接更长的排列。
疑问2:# how does it know that I only want 2 strings?
它根本不知道你“只想要2个字符串”,这是递归的自然结果呀!
举个例子,当处理"cat"时:
- 第一次循环取字符
'c',剩下的子串是"at",调用permute("at")会返回["at", "ta"],所以拼接后得到["cat", "cta"]; - 第二次循环取字符
'a',剩下的子串是"ct",调用permute("ct")返回["ct", "tc"],拼接得到["act", "atc"]; - 第三次循环取字符
't',剩下的子串是"ca",调用permute("ca")返回["ca", "ac"],拼接得到["tca", "tac"]。
所有结果合并起来就是6个排列(3!),而递归到长度为2的字符串时,自然会生成2个排列(2!)——这是算法遍历所有可能组合的必然结果,不是刻意限定的。
时间复杂度:O(n!)是正确的吗?
答案是完全正确,咱们来理清楚原因:
- 排列总数的下限:n个不同字符的排列总数是n!,算法必须生成每一个排列,这部分的工作量至少是O(n!),因为每个排列都要被构造和存储。
- 递归过程的总工作量:对于长度为k的字符串,递归会触发k次对长度为k-1的字符串的调用。把所有递归步骤的工作量加起来:
而n! + (n-1)*(n-1)! + (n-2)*(n-2)! + ... + 1*1! = (n+1)! - 1(n+1)!和n!是同阶的(大O表示法忽略常数倍数),所以总时间复杂度就是O(n!)。 - 最优性:因为必须生成所有n!个排列,所以这个算法的时间复杂度已经是最优的了——不可能有比O(n!)更快的算法来生成所有排列。
内容的提问来源于stack exchange,提问作者edmamerto
相关产品推荐
相关产品推荐

