递归算法的时间复杂性

时间:2012-12-09 21:33:00

标签: algorithm data-structures time-complexity runtime-compilation

每当我看到一个递归解决方案,或者我为问题编写递归代码时,我很难弄清楚时间复杂度,在大多数情况下我只是说它是指数的?实际上它是如何指数的?人们怎么说它是2 ^ n,当它是n !,当它是n ^ n或n ^ k时。

我有一些问题 -

  1. 让我们找一个字符串的所有排列(O(n!))
  2. 找到所有在数组中总和为k的序列(指数,我究竟如何计算)。
  3. 查找大小为k且总和为0的所有子集(k会出现在复杂的某处,它应该是正确的吗?)。
  4. any1可以帮助我如何计算这些问题的确切复杂性,我能够为它们编写代码,但是它很难理解确切的时间复杂度。

2 个答案:

答案 0 :(得分:3)

  

找到所有在数组中总和为k的序列(指数,我究竟如何计算)。

F(a, n, k)S ⊂ {0, 1, ..., n-1}的所有子集的数量,以便

 ∑ a[i] == k
i∈S

然后我们可以通过将问题分成两个子问题(F(array, length of array, k))来递归计算n > 0

{0, 1, ..., n-1}的子集可以分为两类,一类包含n-1,另一类则不包含。{/ p>

我们获得了递归

F(a,n,k) = F(a,n-1,k) + F(a,n-1, k-a[n-1])

T(n)为计算F(_,n,_)所需的时间(下划线表示T(n)仅依赖于n,而不依赖于数组或k } [虽然对于特定的数组和k更快的算法是可能的]。F的递归然后立即暗示

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

代表n > 0

对于n == 0,我们可以在恒定时间内计算解决方案,

F(a, 0, k) = k == 0 ? 1 : 0

所以我们归纳T(n) = 2^n * T(0)

如果不仅要对子集进行计数,而是输出,则复杂度变为O(n * 2^n)并且该边界紧密(对于所有0的数组,k == 0,所有子集符合条件,打印它们需要Θ(n * 2^n)时间。

  

查找大小为k且其总和为0的所有子集(k会出现在复杂的某处,它应该是正确的吗?)。

是的,该问题的复杂性取决于nk

F(a,n,k,s)为基数S ⊂ {0, 1, ..., n-1}的子集k的数量,以便

 ∑ a[i] == s
i∈S

对于k == 0,我们再次有一个恒定的时间答案,如果s == 0,则有一个这样的子集(空集),否则没有。对于k > n,集合{0, 1, ..., n-1}没有基数k的子集,因此如果F(a,n,k,s) = 0则为k > n

如果0 < k <= n,我们可以像上面一样考虑包含n-1的子集和不单独的子集,给出

F(a,n,k,s) = F(a,n-1,k,s) + F(a,n-1,k-1,s - a[n-1])

我们发现的时间复杂度

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

从二项式系数知道递归,我们有

T(n,k) = n `choose` k = n! / (k! * (n-k)!)

T(n,0) = 1)。

再一次,如果集合不仅要计算,而是输出,时间复杂度增加,这里所有集都有基数k,所以它变成

k * n! / (k! * (n-k)!)

答案 1 :(得分:0)

看看Master Theorem。教授完全解释了这一点。 Tim Roughgarden来自斯坦福大学的Algorithms: Design and Analysis: Part I。这是我推荐的在线课程,但您可以在不注册课程的情况下观看视频。如果您有兴趣,也可以参加本课程的第二部分。