数组重复效率之谜

时间:2017-03-16 22:11:42

标签: java arrays duplicates

最近在AP计算机科学A,我们班最近学习了数组。我们的老师向我们提出了一个谜语。 假设您有20个数字,包括10到100,对吧? (这些数字是使用扫描仪从另一个文件中收集的)

当读取每个数字时,我们必须打印该数字,当且仅当它不是已读取的数字的副本时。现在,抓住了。 我们必须使用可能的最小数组来解决问题。

这是我遇到的真正问题。我的所有解决方案都需要一个相当大的阵列,其中有20个插槽。

我需要使用数组。我们可以用来有效解决问题的最小数组是什么?

如果有人能用伪代码(或单词)来解释这个方法,那就太棒了。

6 个答案:

答案 0 :(得分:3)

在最坏的情况下,我们必须使用长度为19的数组。 为什么19?必须记住每个唯一的编号,以便从以下数字中挑选出重复的数字。由于您知道有20个号码传入,但不是更多,您不必存储最后一个号码。第二个数字已经出现(然后什么都不做),或者第二个数字是唯一的(然后打印并退出 - 不需要保存它)。

顺便说一下:我不会调用长度为20的数组:)

答案 1 :(得分:2)

如果您的数字是整数:您的范围是10到100.因此您需要91位来存储已经读取的值。 Java Long有64位。所以你需要一个两个Longs的数组。让每个位(多余的位除外)代表从10到100的数字。用0初始化两个长数。读取数字时,检查映射到读取值的相应位是否设置为1.如果是,则如果没有将该位设置为1,则读取的数字是重复的。

这是BitSet类背后的想法。

答案 2 :(得分:1)

同意Socowi。如果已知数量且它等于N,则始终可以使用N-1阵列来存储重复项。一旦收到输入中的最后一个元素并且已经知道这是最后一个元素,就不需要将这个最后一个值存储在duplicates数组中。

另一个想法。如果您的数字很小并且确实位于[10:100] diapason中,您可以使用1长数来存储至少2个小整数,并使用二进制AND从长数中提取它们以提取小整数值。在这种情况下,可以使用N / 2阵列。但它会使这个数组中的搜索更加复杂,并且不会节省太多内存,只会减少数组中的项目数。

答案 3 :(得分:1)

技术上你不需要数组,因为输入大小是固定的,你可以只声明20个变量。但是,让我们说它没有修复。

正如其他答案所说,最糟糕的情况是阵列中确实有19个插槽。但是,假设我们在这里讨论的是整数,那么有一个更好的情况,其中一些数字形成一个连续的区间。在这种情况下,您只需要记住最高和最低的数字,因为两者之间的任何内容也是重复的。您可以使用 interval 的数组。

在10到100的范围内,数字可以间隔开,在最坏的情况下,您仍需要19个间隔的数组。但是,让我们说,最好的情况发生,并且所有数字形成一个连续的间隔,那么你只需要1个数组插槽。

您仍需要解决的问题是在数组上创建抽象,在添加元素时将其自身扩展为1,因此它将使用所需的最小大小。 (类似于ArrayList,但在达到容量时它的大小增加了一倍。)

答案 4 :(得分:0)

由于数组在运行时无法更改大小您需要一个伴随变量来计算不重复的数字,并仅使用这些数字部分填充数组。

这是一个使用伴随变量currentsize并部分填充数组的简单代码。

备选方案,您可以使用在运行时更改大小的arrayList

final int LENGTH = 20;
double[] numbers = new double[LENGTH];

int currentSize = 0;
Scanner in = new Scanner(System.in);
while (in.hasNextDouble()){
 if (currentSize < numbers.length){
 numbers[currentSize] = in.nextDouble();
 currentSize++;
 }
}

修改

现在currentSize包含那些不重复的实际数字,并且如果您有一些重复项,则不会填充所有20个元素。当然,您需要一些代码来确定数字是否重复。

答案 5 :(得分:0)

我的最后一个答案误解了你的需求,但是我把这个问题转化为使用位移的5个元素的int数组。由于我们知道最大数量为100,因此我们可以将四个数字存储(相当混乱)到每个索引中。

    Random rand = new Random();

    int[] numbers = new int[5];
    int curNum;

    for (int i = 0; i < 20; i++) {

        curNum = rand.nextInt(100);

        System.out.println(curNum);

        boolean print = true;
        for (int x = 0; x < i; x++) {

            byte numberToCheck = ((byte) (numbers[(x - (x % 4)) / 4] >>> ((x%4) * 8)));

            if (numberToCheck == curNum) {

                print = false;

            }

        }

        if (print) {

            System.out.println("No Match: " + curNum);

        }

        int index = ((i - (i % 4)) / 4);
        numbers[index] = numbers[index] | (curNum << (((i % 4)) * 8));

    }

我使用rand来获取我的内容,但你可以轻松地将其更改为扫描仪。