Java 枚举子集的空间复杂度是多少?

Java 枚举子集的空间复杂度是多少?,java,algorithm,recursion,time-complexity,space-complexity,Java,Algorithm,Recursion,Time Complexity,Space Complexity,这是基于我关于空间复杂性的另一个问题 这是我枚举(命名)所有集合的问题的解决方案。(经过测试,效果良好) 公共静态无效子集(集合s){ 队列copyToProtectData=newlinkedlist(); for(国际成员:s){ copyToProtectData.add(成员); } 生成子集(copyToProtectData,newhashset()); } 专用静态void生成子集(队列, 集(哈希集){ 如果(s.isEmpty()){ System.out.println(ha

这是基于我关于空间复杂性的另一个问题

这是我枚举(命名)所有集合的问题的解决方案。(经过测试,效果良好)

公共静态无效子集(集合s){
队列copyToProtectData=newlinkedlist();
for(国际成员:s){
copyToProtectData.add(成员);
}
生成子集(copyToProtectData,newhashset());
}
专用静态void生成子集(队列,
集(哈希集){
如果(s.isEmpty()){
System.out.println(hashSet);
}否则{
int member=s.remove();
Set copy=new HashSet();
for(int i:hashSet){
副本.添加(i);
}
hashSet.add(成员);
Queue queueCopy=new LinkedList();
用于(int i:s){
添加(i);
}
生成子集(s,哈希集);
生成子集(队列复制,复制);
}
}

我知道我的算法的时间复杂度是O(2n),因为离散数学中的一个解是集合n有2n个子集。这是评估该算法时间复杂度的一种可接受的方法吗(找不到递归关系来实现)

然而,继续下去,我仍然难以评估空间的复杂性。我正在尝试运用我从上一个问题中学到的知识。在我最后一个关于字符串排列的问题中,@ajb说,由于我存储了一个在每次递归调用时增长1的本地字符串,所以我的空间复杂度实际上是O(n2)


我正试图在这里应用同样的方法。假设我的测试集是{1,2,3}。根据我的算法生成子集{1,2,3},当{1,2,3}最终打印出来时,这些“子集”也存在于内存中,{1},{1,2},{1],{1,2,3},{1,2},这意味着它不仅仅是一个少了一个元素的子集,就像排列问题一样。我还在每一轮中复制剩余的元素,这样一边的一个操作不会影响另一边的复制。这就是为什么我不确定@ajb的策略在这里是否有效。运行时仍然是O(n2)吗或者它是更大的吗?

如果你想要一个好的边界,通常你分析复杂性的方法是通过混合使用和其他方法——例如,你可以尝试以迭代的形式重写递归,以便于分析

更直接地回答您的问题:您的运行时不是O(2^n)

代码的这些部分将使复杂性增加到O(n*2^n)

原因是您不仅要迭代每个子集,还要迭代每个子集的每个元素


关于你的空间复杂度问题,假设垃圾收集是最重要的,那么是的,空间复杂度是O(n^2)。即使你复制的是2个而不是1个,复杂度仍然是O(n^2)因为这只会影响常量因子。如果你真的想保存所有子集的列表,那么空间复杂度会一直增加到O(n*2^n)-您当前仍然需要用于输出。

您可以使用双变量递归关系解决此问题。方法调用的时间复杂性取决于
s
的大小和哈希集的大小(我们称之为
h
)。然后:

我们感兴趣的是
T(n,0)
。对于空间复杂度,同样的递归关系成立,除了
S(0,h)=0
。这假设所创建的集合永远不会被销毁

T(s,…)
的每个实例生成两个
T(s-1,…)
实例。我们从
T(n,…)
开始,最后是
2^n
实例
T(0,…)=O(1)

T(n, 0) = 2^n * O(1) + ...
此外,我们必须考虑生成的
h
s和
s-1
s。让我们从
s-1
s开始。在第一次扩展之后,将有1个
n-1
。在第二次扩展之后,将有另外两个
n-2
。在第三次扩展之后,将增加4个
n-3
…和
n
扩展执行生成这些项的运算。总计:
Sum{i from 1 to n}(2^(i-1)*(n-i))=2^n-n-1
。因此:

T(n, 0) = 2^n * O(1) + O(2^n - n - 1) + ...
最后是
h
项。这有点棘手。第一次展开只会得到一个零项。下一次展开会得到一个
1
项和一个
0
项。然后是一个
2
,两个
1
,一个
0
。这个数字始终等于二项式系数:
和{e从0到n-1}(和{i从0到e}(i*Binom(e,i))=1-(n-1)*2^n
。最后:

T(n, 0) = 2^n * O(1) + O(2^n - n - 1) + O(1 - (n-1)*2^n)
        = O(n*2^n)

如果保留所有创建的集合,则相同的复杂性适用于空间要求。

“这是评估时间复杂性的一种可接受的方法吗?”-不。你的算法复杂性可能与你的问题的基本数学理论无关。那么你会怎么做?你会使用什么递归关系?好的,没有递归关系来列出一个集合的所有子集。那么你如何证明子集解的时间复杂性呢?嗯,谢谢,但是你怎么做我要用迭代的形式来写这个问题吗?我被教导解决这个问题的方法是使用递归来减少你的可能性集,直到它为空。你能再解释一下吗?每次调用都会为两个集合中的每个迭代元素分配空间。因此,分配的空间量应该与单次传递的运行时间成比例(没有递归调用)。空间复杂度和时间复杂度有何不同?我目前正在解决重复问题,但这似乎相当困难。@NicoSchertler如果重复使用空间,空间复杂度可能不同于时间复杂度-即,如果我想打印出数字1到N,如果我制作一个数组来存储所有数字,然后打印出来,这需要O(N)空间。如果我只有一个变量并进行迭代,在进行打印时,它需要O(1)空间。@co
T(n, 0) = 2^n * O(1) + ...
T(n, 0) = 2^n * O(1) + O(2^n - n - 1) + ...
T(n, 0) = 2^n * O(1) + O(2^n - n - 1) + O(1 - (n-1)*2^n)
        = O(n*2^n)