繁体   English   中英

这种情况下bitset的空间复杂度是多少

[英]What is the space complexity of bitset in this scenario

我正在做一个 leetcode 问题,我必须找到一个大小为 [1-N] 的数组的副本,并找到了这个解决方案:

    public int findDuplicate(int[] nums) {
        BitSet bit = new BitSet();
        for(int num : nums) {
            if(!bit.get(num)) {
                bit.set(num);
            } else {
                return num;
            }
        }
        return -1;
    }

我假设在这里使用 bitset 类似于使用 boolean[] 来跟踪我们之前看到的当前数字。 所以我的问题是空间复杂度是多少? 运行时似乎是 O(n),其中 n 是输入数组的大小。 空间复杂度也是如此吗?

问题链接: https://leetcode.com/problems/find-the-duplicate-number/

您的Bitset创建一个底层long[]来存储值。 阅读Bitset#set的代码,我可以肯定地说数组永远不会大于max(nums) / 64 * 2 = max(nums) / 32 由于long具有固定大小,因此归结为O(max(nums)) 如果nums包含较大的值,您可以使用 hash map 做得更好。

我正在用简单的代码尝试这个,它似乎证实了我对代码的阅读。

BitSet bitSet = new BitSet();

bitSet.set(100);
System.out.println(bitSet.toLongArray().length); // 2 (max(nums) / 32 = 3.125)

bitSet.set(64000);
System.out.println(bitSet.toLongArray().length); // 1001 (max(nums) / 32 = 2000)

bitSet.set(100_000);
System.out.println(bitSet.toLongArray().length); // 1563 (max(nums) / 32 = 3125)

请注意,我添加的2因子是保守的,通常它会是一个较小的因子,这就是为什么我的公式始终高估长数组的实际长度,但绝不会超过 2 的因子。这是代码Bitset我添加它的位集:

private void ensureCapacity(int wordsRequired) {
    if (words.length < wordsRequired) {
        // Allocate larger of doubled size or required size
        int request = Math.max(2 * words.length, wordsRequired);
        words = Arrays.copyOf(words, request);
        sizeIsSticky = false;
    }
}

总之,如果您有理由相信您的值小于您的值(计数),我会说位设置只是一个好主意。 例如,如果您只有两个值,但它们的值超过十亿,您将不必要地分配一个包含几百万个元素的数组。

此外,即使在值仍然很小的情况下,此解决方案对于已排序的 arrays 的性能也很差,因为Bitset#set将始终重新分配和复制数组,因此您的复杂性根本不是线性的,它是max(nums)的二次方,这可能很糟糕如果max(nums)非常大。 要线性,您需要首先找到最大值,在Bitset中分配必要的长度,然后通过数组仅分配 go。

此时,使用 map 更简单,适用于所有情况。 如果速度真的很重要,我敢打赌Bitset将在特定条件下击败 map(很多值,但很小,并且通过按所述预先调整位集的大小)。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM