查找内存有限的重复元素

时间:2016-07-24 20:18:50

标签: java arrays memory scalability

以下是Cracking the coding采访中提出的一个问题:

  

你有一个数组从1到N的所有数字,其中N最多   32,000。该数组可能有重复的条目,你不知道是什么   N是。只有4KB的可用内存,您将如何打印所有内存   数组中的重复元素?

方法签名是

SELECT t.*
FROM t
WHERE t.col2 IN (5, 7, 9) AND
      t.col1 IN (SELECT col1
                 FROM t
                 WHERE col1 > 1645 AND col2 IN (5, 7, 9)
                 GROUP BY col1
                 HAVING COUNT(DISTINCT col2) = 3
                );

然后解决方案解释了如何使用位向量来解决这个问题,方法是将每个整数表示为一个位。我的困惑是当我们运行这个方法时,它不会将整个数组加载到内存中以循环它吗?现在,如果public static void checkDuplicates(int[] array) 的大小有,例如,10亿(许多重复的元素)将不会失败,因为它将整个数组加载到内存中,而我们的内存是array位?

5 个答案:

答案 0 :(得分:4)

这可能是一个棘手的问题。我最近在谷歌接受了采访,他们遇到了类似你的问题。我认为最好在这些情况下解释你的思路并涵盖每个案例。这些问题也是由人类构建的,所以他们可能错过了一个单词等。如果我不得不回答这个问题,我会想出多个答案:

  • 所有内存使用量可能是4KB(问题等)
  • 您的解决方案应符合4KB(上述解决方案)

案文说:

  

只有4KB的可用内存[...]

因为Java是terms of passing values中一种有趣的语言,所以在传递给方法时,不会创建int数组的新实例。

public class Test {
    public static void main(String[] args) {
        int[] stuff = {1};
        System.out.println("before: " + stuff[0]);
        doStuff(stuff);
        System.out.println("after: " + stuff[0]);
    }
    public static void doStuff(int[] array){
        array[0]=10;
    }
}

由于这种行为,您的4KB可用于内部处理算法。我认为这种限制只是为了防止“我复制它和......”的解决方案。

答案 1 :(得分:4)

以下是经过测试的代码:

public void checkDuplicates(int[] nums){
    int bytesNeeded = (nums.length/8) + 1;
    byte[] bitSet = new byte[bytesNeeded];

    for(int i=0; i<nums.length; i++){
        int n = nums[i];
        int byteIndex = n / 8;
        int indexInByte = n % 8;

        byte bit = (byte)(bitSet[byteIndex] & (1 << indexInByte));
        if(bit > 0){
            System.out.print(nums[i] + " ");
        }else{
            bitSet[byteIndex] |= 1 << indexInByte; 
        }
    }
}

答案 2 :(得分:0)

4Ko似乎是函数的允许内存量而不是整个程序,甚至没有,在这种情况下将内存内容交换到文件中会非常有用{。{3}}。

答案 3 :(得分:0)

完成任务的平均值&#34; 4KB&#34;所以你的代码并不意味着占用更多的空间。这里的代码在我的脑海中被编写但尚未经过测试。

基本上只需使用数字的值作为位向量中的索引。 如果已经设置,则打印消息;否则设置它。

public class BitVectorMagic {
    static public void checkDuplicates(final int[] pArray) {
        final int neededBytes = (pArray.length / 8) + 1;
        final byte[] bitVector = new byte[neededBytes];

        for (int i = 0; i < pArray.length; i++) {
            final int value = pArray[i];
            final int byteIndex = value / 8;
            final int indexInByte = value % 8;

            final byte bitByte = bitVector[byteIndex];
            final byte bit = getBit(bitByte, indexInByte);
            if (bit > 0) {
                System.out.println("Duplicate value " + value + " at pos " + i);
            } else {
                final byte writeBitByte = setBit(bitByte, indexInByte);
                bitVector[byteIndex] = writeBitByte;
            }
        }
    }


    private static byte setBit(final byte pBitByte, final int pIndexInByte) {
        final byte or = (byte) (0x01 << pIndexInByte);
        return (byte) (pBitByte | or);
    }


    static private byte getBit(final int pByte, final int pIndexInByte) {
        return (byte) ((pByte >> pIndexInByte) & 1);
    }
}

答案 4 :(得分:0)

问题的想法是32000 (possible values) / 8 (bit in byte) = 4000 ~ 4096 (4 KB)

初始数组内存不计算,因为它的大小没有合理的限制,因为没有给出重复数量的限制。

4 KB是方法可以使用的内存量,并且由于该方法接收到指向输入数组的指针(不需要复制其值),因此不会计算数组大小。

据我所知,任何O(N)内存估计都会考虑额外的内存算法可以用来解决问题。