每当我看到一个递归解决方案,或者我为问题编写递归代码时,我很难弄清楚时间复杂度,在大多数情况下我只是说它是指数的?实际上它是如何指数的?人们怎么说它是2 ^ n,当它是n !,当它是n ^ n或n ^ k时。
我有一些问题 -
any1可以帮助我如何计算这些问题的确切复杂性,我能够为它们编写代码,但是它很难理解确切的时间复杂度。
答案 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会出现在复杂的某处,它应该是正确的吗?)。
是的,该问题的复杂性取决于n
和k
。
让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。这是我推荐的在线课程,但您可以在不注册课程的情况下观看视频。如果您有兴趣,也可以参加本课程的第二部分。