查找具有最小下一次出现的第一个副本

时间:2018-03-25 00:12:11

标签: java

我正在努力解决挑战, 我写了我的解决方案,除了一些隐藏的测试用例外,它传递了所有测试用我无法想到另一个案例,我的方法失败了,不知道该怎么做了。 这是:

int firstDuplicate(int[] a) {

int[]   indexCount;
int     duplicate, temp;
boolean check;

duplicate  = -1; temp = a.length;
indexCount = new int[a.length];
check      = false;

for( int i = 0; i < a.length; i++ ){

    if( indexCount[a[i]-1] == 0 ){
        indexCount[a[i]-1] = i+1;
        check = false;
    }else{
        indexCount[a[i]-1] = (i+1) - indexCount[a[i]-1];
        check = true;
    }
    if( check && indexCount[a[i]-1] < temp ){
        duplicate = a[i];
        temp      = indexCount[a[i]-1];
    }
}
return duplicate;

}

说明是:

编写具有O(n)时间复杂度和O(1)额外空间复杂度的解决方案。 给定一个仅包含1到a.length范围内的数字的数组a,找到第二个匹配项具有最小索引的第一个重复数字。

实施例

对于a = [2,3,3,1,5,2],输出应为 firstDuplicate(a)= 3.

有两个重复:数字2和3.第二次出现的3的索引小于第二次出现的2,所以答案是3。

对于a = [2,4,3,5,1],输出应为 firstDuplicate(a)= -1。

2 个答案:

答案 0 :(得分:3)

这就是我所拥有的。在O(n)中运行并使用O(1)空间。如果我在这里错了,请纠正我。

由于我的输入的值不能超过长度,我可以使用mod运算符对同一个数组进行索引,并将长度添加到index中的值。一旦我遇到一个大于长度的值,这意味着我之前已经增加了它,这给了我重复的值。

public int firstDuplicate(int[] arr) {
    int length = arr.length;

    for (int i = 0; i < length; i++) {
        int expectedIndex = arr[i] % length;
        if (arr[expectedIndex] > length) {
            return arr[i] > length ? arr[i] - length : arr[i];
        } else {
            arr[expectedIndex] += length;
        }
    }

    return -1;
}

答案 1 :(得分:1)

此答案基于@Mehmet-Y's answer,所有功劳归于Mehmet-Y。这个版本解决了我在comments中指出的三个问题。如果原件得到纠正,我会删除这个答案。

一般方法是使用原始数组进行存储,而不是分配新数组。没有值可能小于一个或大于长度的事实表明你可以使用数组作为一组索引来标记元素为&#34;已经看到&#34;通过否定它或向/从中添加/减去数组长度。

要实现O(n)时间复杂度,您必须在固定数量的传递中解决问题(不一定是一次传递:数字不能取决于数组的大小)。

但是,您如何确定哪个副本具有最小的第二索引?我建议使用两个不同的标志来表示已经看到的索引与重复对中的第二个项目。对于此示例,我们可以通过按长度递增元素来设置索引标志,并通过否定它们来标记重复项。你将需要第二遍来找到数组中的第一个否定。您还可以使用该传递将元素恢复为原始值,而不会牺牲O(n)时间复杂度。

以下是一个示例实现:

int firstDuplicate(int[] a)
{
    // assume all elements of a are in range [1, a.length]
    // An assertion of that would not increase the time complexity from O(n)
    int len = a.length;
    for(int i = 0; i < len; i++) {
        // a[i] may be > len, but not negative.
        // Index of bin to check if this element is already seen.
        flagIndex = (a[i] - 1) % len;
        if(a[flagIndex] > len) {
            // If already seen, current element is the second of the pair.
            // It doesn't matter if we flag the third duplicate,
            // just as long as we don't tag the first be accident.
            a[i] = -a[i];
        } else {
            // Flag the element as "already seen".
            // This can be done outside the else, but you might run
            // into (more) overflow problems with large arrays.
            a[flagIndex] += len;
        }
    }
    // Search and stash index of first negative number
    for(int i = 0; i < len; i++) {
        if(a[i] < 0) {
            return -a[i] % len;
        }
    }
    // Nothing found, oh well
    return -1;
}

如果您想利用第二遍来恢复数组的原始值,请替换

for(int i = 0; i < len; i++) {
    if(a[i] < 0) {
        return -a[i] % len;
    }
}
return -1;

int duplicate = -1;
for(int i = 0; i < len; i++) {
    if(a[i] < 0) {
        a[i] = -a[i];
        if(duplicate == -1) {
            duplicate = a[i] % len;
        }
    }
    a[i] %= len;
}
return duplicate;