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