Math 为什么powerset的时间复杂度为2^N?

Math 为什么powerset的时间复杂度为2^N?,math,recursion,discrete-mathematics,recurrence,Math,Recursion,Discrete Mathematics,Recurrence,以下是用于生成功率集的递归函数 void powerset(int[] items, int s, Stack<Integer> res) { System.out.println(res); for(int i = s; i < items.length; i++) { res.push(items[i]); powerset(items, s+1, res); res.pop();

以下是用于生成功率集的递归函数

void powerset(int[] items, int s, Stack<Integer> res) {
     System.out.println(res);

     for(int i = s; i < items.length; i++) {
          res.push(items[i]);
          powerset(items, s+1, res);
          res.pop();
     }
}
void powerset(int[]项、int s、堆栈res){
系统输出打印项次(res);
对于(int i=s;i
我真的不明白为什么这需要
O(2^N)
。那
2
是从哪里来的? 为什么
T(N)=T(N-1)+T(N-2)+T(N-3)+T(1)+T(0)
解为
O(2^n)
。有人能解释一下原因吗?

类似这样的事情

T(1)=T(0)

T(2)=T(1)+T(0)=2T(0)

T(3)=T(2)+T(1)+T(0)=2T(2)

因此,我们有


T(N)=2T(N-1)=4T(N-2)=2^(N-1)T(1),也就是O(2^N)

我可以用几种数学方法向你们解释第一种:

考虑像
a
这样的一个元素,每个子集有两个关于
a
的选项,要么它们有要么没有,因此我们必须有
$2^n$
子集,因为您需要为创建每个子集调用函数,所以您需要调用此函数
$2^n$

另一个解决方案:

这个解决方案就是这个递归,它产生了一个方程,让我定义
T(0)=2
对于一个有一个元素的集合,我们有T(1)=2,你只要调用函数,它就结束了。现在假设对于每个具有
k
元素的集合,我们有这个公式

T(k)=T(k-1)+T(k-2)+…+T(1)+T(0)(我称之为*公式)

我想证明,对于k=n,这个方程是正确的

考虑每个有第一个元素的子集(就像你在算法开始时做的那样,你推第一个元素),现在我们有n-1个元素,所以需要
T(n-1)
才能找到每个有第一个元素的子集。到目前为止,我们已经:

T(n)=T(n-1)+T(没有第一个元素的子集)(我称之为**公式)

for
循环的末尾,您删除了第一个元素,现在我们有了每个没有第一个元素的子集,就像我在(**)中所说的,并且您有
n-1
元素,因此我们有:

T(没有第一个元素的子集)=T(n-1)(我称之为*公式)

根据公式(*)和(*),我们有:

T(没有第一个元素的子集)=T(n-1)=T(n-2)+…+T(1)+T(0)(我称之为****公式)

现在我们从第一个公式()和(**)中得到了您想要的:

T(n)=T(n-1)+T(n-2)+…+T(1)+T(0)


而且我们还有
T(n)=T(n-1)+T(n-1)=2*T(n-1)
所以
T(n)=$2^n$

每当我们决定向原始数组中添加另一个元素时,我们所做的操作数都会加倍

例如,假设我们只有空集{}。如果我们想添加{a},幂集会发生什么变化?然后我们将有两个集合:{},{a}。如果我们想添加{b}呢?然后我们将有4个集合:{},{a},{b},{ab}

注意2^n也意味着加倍的性质。
下面是更一般的解释。 请注意,发电机组基本上是发电组合。 (nCr是可通过从总n项中选取r项进行组合的数量)

例如:{1,2,3}的幂集是{{{}、{1}、{2}、{3}、{1,2}、{2,3}、{1,3}{1,2,3}=8=2^3

1) 3C0 = #combinations possible taking 0 items from 3 = 3! / ((3-0)! * 0!) = 1
2) 3C1 = #combinations possible taking 1 items from 3 = 3! / ((3-1)! * 1!) = 3
3) 3C2 = #combinations possible taking 2 items from 3 = 3! / ((3-2)! * 2!) = 3
4) 3C3 = #combinations possible taking 3 items from 3 = 3! / ((3-3)! * 3!) = 1
如果你把4加起来,结果是1+3+3+1=8=2^3。所以基本上,它是n个项的幂集合中的2^n个可能集合


所以在一个算法中,如果你用所有这些组合生成一个功率集,那么它需要的时间与2^n成正比。因此,时间复杂度为2^n。

Shriganesh Shintre的答案很好,但你可以进一步简化:

假设我们有一个集合S:

{a1,a2,…,aN}

现在我们可以编写一个子集s,其中集合中的每个项都可以有值1(包含)或0(排除)。现在我们可以看到,可能的集合s的数量是:


2*2*…*2
2^N

它来自给定的公式T(N)=T(N-1)+T(N-2)+…+T(1)+T(0);我假设它在N=1时成立。否则你需要用不等式代替方程,方程为T(1)>=T(0);2T(1)>=T(2)>=2T(0)等等。结果保持不变,但这可能更适合cs.stackexchange.com(或math..),首先,您的算法是
O(N*2^N)
。打印不是免费的(它是
O(n)
),而且构建实际的数组集肯定也不是
O(1)
。如果n个元素中的每一个都包含在一半的子集(即2n-1子集)中,这不是n2^n吗?@Leandro不,
n
是一个很好的解释!我担心的是我发现很难从
nCr=n跳转/(右)
2^n
的结论。实际上,通过观察几个基本情况,它与
2^n
的结果相匹配。但是考虑到像你在面试中解释复杂性这样的情况,我不确定给出基本案例是否足以概括,我觉得
sum(nCr)
2^n
之间存在差距。我还发现很难从代码结构中推断
2^n
。不知道是否有人有同样的担心,还是只有我。
1) 3C0 = #combinations possible taking 0 items from 3 = 3! / ((3-0)! * 0!) = 1
2) 3C1 = #combinations possible taking 1 items from 3 = 3! / ((3-1)! * 1!) = 3
3) 3C2 = #combinations possible taking 2 items from 3 = 3! / ((3-2)! * 2!) = 3
4) 3C3 = #combinations possible taking 3 items from 3 = 3! / ((3-3)! * 3!) = 1