这个子集算法的空间复杂度实际上是O(n)吗?

时间:2015-03-24 05:32:19

标签: java algorithm recursion time-complexity space-complexity

这是Cracking the Coding Interview 5 th 的问题9.4 问题:编写方法以返回集合的所有子集。

这是我在Java中的解决方案。(测试它,它有效!!!)

public static List<Set<Integer>> subsets(Set<Integer> s) {
    Queue<Integer> copyToProtectData  = new LinkedList<Integer>();
    for(int member: s) {
        copyToProtectData.add(member);
    }
    List<Set<Integer>> subsets = new ArrayList<Set<Integer>>();
    generateSubsets(copyToProtectData, subsets, new HashSet<Integer>());
    return subsets;
}
private static void generateSubsets(Queue<Integer> s, 
        List<Set<Integer>> subsets, Set<Integer> hashSet) {
    if(s.isEmpty()) {
        subsets.add(hashSet);
    } else {
        int member = s.remove();
        Set<Integer> copy = new HashSet<Integer>();
        for(int i:hashSet) {
            copy.add(i);
        }
        hashSet.add(member);
        Queue<Integer> queueCopy = new LinkedList<Integer>();
        for(int i:s){
            queueCopy.add(i);
        }
        generateSubsets(s, subsets, hashSet);
        generateSubsets(queueCopy, subsets, copy);          
    }
}

我查看了这个问题的解决方案,作者说这个算法的解决方案是在 O(2 n 时间复杂度和 O(< 2 n 空间复杂性。我同意她的说法,这个算法在 O(2 n 时间运行,因为要解决这个问题,你必须考虑到这样一个事实:对于任何元素,你有两种可能性,它可以在集合中,也可以不在集合中。并且因为你有n个元素,你的问题将有2个 n 的可能性,所以问题将通过O(2 n )时间来解决。

但是我相信我有一个令人信服的论据,即我的算法在 O(n)空间中运行。我知道空间复杂度是算法相对于输入大小所占的总空间&#34; Space Complexity并且与递归调用的深度有关(请记住我观看过的一些Youtube视频)

我的一个例子是生成[1,2,3]作为[1,2,3]的子集。这是生成该组的递归调用集 generateSubsets([],子集,[1,2,3])
generateSubsets([3],子集,[1,2])
generateSubsets([2,3],子集,[1])
generateSubsets([1,2,3],子集,[])

这表明相对于原始集合大小n的递归调用的最大深度是n本身。这些递归调用中的每一个都有自己的堆栈帧。因此,我得出结论,空间复杂度是 O(n)我的证据中是否有人看到任何缺陷?

1 个答案:

答案 0 :(得分:4)

您需要考虑算法分配的所有内存(或者更确切地说,任何时候“正在使用”的最大分配内存量) - 不仅在堆栈上,而且在堆上。每个生成的子集都存储在subsets列表中,最终将包含2个 n 集,每个集的大小介于0和 n之间(大多数集合包含 n / 2个元素) - 所以空间复杂度实际上是 O n 2 < SUP> 名词 )。