在一个数组中找到所有加起来等于k的序列(指数级别,如何精确计算)。
令
F(a, n, k)
为集合
S ⊂ {0, 1, ..., n-1}
的所有子集的数量,使得:
∑ a[i] == k
i∈S
我们可以通过将问题分成两个子问题(对于n>0
)来递归计算F(array,array的长度,k)
。
{0,1,...,n-1}
的子集可以分为包含n-1
和不包含n-1
的两类。
我们得到递归公式:
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)
是元素集合 {0, 1, ..., n-1}
中所有大小为 k
,满足以下条件的子集S
的数量:
∑ a[i] == s
i∈S
对于
k == 0
,我们再次有一个常数时间的答案,如果
s == 0
,则存在一种这样的子集(空集),否则不存在。 对于
k > n
,集合
{0, 1, ..., n-1}
没有基数为
k
的子集,因此如果
k > n
,则
F(a,n,k,s) = 0
。
如果
0 < k <= n
,我们可以像上面一样,分别考虑包含
n-1
和不包含
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)!)