Java 在时间复杂度O(n)和空间复杂度O(1)的数组中查找重复元素的最有效算法是什么?

Java 在时间复杂度O(n)和空间复杂度O(1)的数组中查找重复元素的最有效算法是什么?,java,data-structures,Java,Data Structures,注意-您不能使用集合或映射 我已经试过了,但它没有复杂性O(n) 类元素 { 无效打印重复(整数arr[],整数大小) { int i,j; System.out.println(“重复元素为:”); 对于(i=0;i

注意-您不能使用集合或映射

我已经试过了,但它没有复杂性O(n)

类元素
{ 
无效打印重复(整数arr[],整数大小)
{ 
int i,j;
System.out.println(“重复元素为:”);
对于(i=0;i

是否有任何一个解决方案,可以在不使用集合或映射的情况下找到一个重复的数组,并且只使用单for循环

确定,因此您对
int
类型的数组有一个恒定的内存需求?
没问题,让我们使用一个大的(但恒定的)
byte
数组:

byte[] seen = new byte[536870912];
byte[] dups = new byte[536870912];
for (int i : arr) {
    int idx = i / 8 + 268435456;
    int mask = 1 << (i % 8);
    if ((seen[idx] & mask) != 0) {
        if ((dups[idx] & mask) == 0) {
            System.out.print(i + " ");
            dups[idx] |= mask;
        }
    } else {
        seen[idx] |= mask;
    }    
}
byte[]seen=新字节[536870912];
字节[]dups=新字节[536870912];
用于(int i:arr){
int idx=i/8+268435456;

int mask=1由于它们是
int
s,您可以使用
位集

void printRepeating(int arr[], int size) {
    BitSet bits = new BitSet();
    BitSet repeated = new BitSet();

    //to deal with negative ints:
    BitSet negativeBits = new BitSet();
    BitSet negativeRepeatedBits = new BitSet();

    for(int i : arr) {
        if(i<0) {
            i = -i; //use the absolute value
            if(negativeBits.get(i)) {
                //this is a repeat
                negativeRepeatedBits.set(i);
            }
            negativeBits.set(i);
        } else {
            if(bits.get(i)) {
                //this is a repeat
                repeated.set(i);
            }
            bits.set(i);
        }
    }
    System.out.println(
            IntStream.concat(negativeRepeatedBits.stream().map(i -> -i), repeated.stream())
                .mapToObj(String::valueOf)
                .collect(Collectors.joining(", ", "Repated Elements are : ", ""))
        );
}
void打印重复(int-arr[],int-size){
位集位=新位集();
重复的位集=新的位集();
//要处理负整数,请执行以下操作:
BitSet NegativeEBITs=新的位集();
比特集negativeRepeatedBits=新比特集();
用于(int i:arr){
if(i-i),repeated.stream())
.mapToObj(字符串::valueOf)
.collect(收集器。连接(“,”,“repatted”元素为:“,”))
);
}

请注意(根据注释)负值需要单独处理,否则,如果大小为
n
的数组中的元素在
0~n-1
的范围内(或
1~n
),您可能会遇到
indexootfboundsexception

我们可以尝试通过将
a[i]
放入索引
i
来对数组进行排序,对于每个
a[i]!=i
,如果我们发现索引
i
处已经有一个
a[i]
,这意味着有另一个值为
a[i]
的元素

for (int i = 0; i < a.length; i++){
  while (a[i] != i) {
    if (a[i] == a[a[i]]) {
      System.out.print(a[i]);
      break;
    } else {
      int temp = a[i];  // Putting a[i] to index i by swapping them
      a[i] = a[a[i]];
      a[temp] = temp;
    }
  }
}
for(int i=0;i
因为在每次交换之后,其中一个元素将处于正确的位置,因此最多会有n次交换操作

时间复杂度O(n)
空间复杂度O(1)对于循环只有一个,
i
将在
j
位于数组末尾时增加,在找到新的重复元素之前找到当前的
arr[i]

    void printRepeatingSingleLoop(int arr[], int size)
    {
        int i, j, k;
        System.out.println("Repeated Elements are :");
        for (i = 0, j = 1, k = 0; i < size; )
        {
            if (k < i ) {
                if (arr[i] == arr[k]) {
                    i++;
                    j = i+1;
                    k = 0;
                } else {
                    k++;
                }
            } else {
                if (j == size) {
                    i++;
                    j = i + 1;
                    k = 0;
                } else {
                    if (arr[i] == arr[j]) {
                        System.out.print(arr[i] + " ");
                        i++;
                        j = i + 1;
                        k = 0;
                    } else {
                        j++;
                    }
                }
            }
        }
        System.out.println();
    }
void printing repeatingsingleloop(int arr[],int size)
{
int i,j,k;
System.out.println(“重复元素为:”);
对于(i=0,j=1,k=0;i
关键是使用集合。检查这个问题:我已经指示我们不能使用集合,并且只会使用一个for循环used@pedrohreis我不这么认为,因为据我所知,OP不允许使用
集合
集合
s实现
集合
。。如果你说的是
映射
s,你是正确的。你能对数组包含的内容进行任何计算吗?一种空间效率非常低的方法是创建一个布尔标记数组,如果该数字之前是否找到过。对于输入中的每个元素,你检查数组中的标志是否为真;如果是,则重复元素,否则将位置标记为已访问。然而r、 这看起来真的很像家庭作业,在现实生活中你会使用一套方法谢谢你的贡献,如果还有其他方法,我想知道,不使用byte[]seen=new byte[536870912]这是你应得的一票,但我没有多少报告可投you@Johanes它工作得很好,但是为什么我们要使用常量字节数组,如果元素是以十亿为单位的大数字,那么会发生什么呢?它是一个常量。请再次阅读如何使用大O表示法,什么是渐近复杂性,以及为什么常量不重要。@JimMischel也许我不是这不是很好的字里行间阅读。In说他们不知道范围。如果你有其他信息,请编辑问题并将这些详细信息添加到中。虽然使用位集似乎是正确的做法,但它是正确的。感谢@JohannesKuhn指出这一点。我已编辑以解决该陷阱。几乎正确。OP想要打印所有重复元素,因此在
a[i]==a[a[i]
的情况下,您将希望
中断
,而不是
返回
。如果有两个以上的重复项,则您的代码无法正常工作
    void printRepeatingSingleLoop(int arr[], int size)
    {
        int i, j, k;
        System.out.println("Repeated Elements are :");
        for (i = 0, j = 1, k = 0; i < size; )
        {
            if (k < i ) {
                if (arr[i] == arr[k]) {
                    i++;
                    j = i+1;
                    k = 0;
                } else {
                    k++;
                }
            } else {
                if (j == size) {
                    i++;
                    j = i + 1;
                    k = 0;
                } else {
                    if (arr[i] == arr[j]) {
                        System.out.print(arr[i] + " ");
                        i++;
                        j = i + 1;
                        k = 0;
                    } else {
                        j++;
                    }
                }
            }
        }
        System.out.println();
    }