简体   繁体   English

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

[英]What is the most efficient algorithm to find repeated elements in an array in time complexity O(n) and space complexity O(1)?

Note- You can not use Collection or Map注意 -您不能使用 Collection 或 Map

I have tried this but this is not having complexity O(n)我已经尝试过了,但这没有复杂性 O(n)

class RepeatElement  
{ 
    void printRepeating(int arr[], int size)  
    { 
        int i, j; 
        System.out.println("Repeated Elements are :"); 
        for (i = 0; i < size; i++)  
        { 
            for (j = i + 1; j < size; j++)  
            { 
                if (arr[i] == arr[j])  
                    System.out.print(arr[i] + " "); 
            } 
        } 
    } 

    public static void main(String[] args)  
    { 
        RepeatElement repeat = new RepeatElement(); 
        int arr[] = {4, 2, 4, 5, 2, 3, 1}; 
        int arr_size = arr.length; 
        repeat.printRepeating(arr, arr_size); 
    } 
} 

Is any one having solution for solving,to find a duplicate array without using Collection or Map and using only single for loop是否有任何人有解决方案,在不使用 Collection 或 Map 并且仅使用单个 for 循环的情况下找到重复数组

If the elements in an array with size n are in a range of 0 ~ n-1 ( or 1 ~ n ).如果数组中大小n的元素在0 ~ n-1 (或1 ~ n )的范围内。

We can try to sort the array by putting a[i] to index i for every a[i] != i , and if we find that there is already an a[i] at index i , it means that there is another element with value a[i] .我们可以尝试通过将每个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;
    }
  }
}

Since after every swap, one of the elements will be in the right position, so there will be at most n swap operations.由于每次交换后,其中一个元素都会在右边的 position 中,所以最多会有 n 次交换操作。

Time complexity O(n)时间复杂度 O(n)

Space complexity O(1)空间复杂度 O(1)

Ok, so you have a constant memory requirement for an array of type int ?好的,所以您对int类型的数组有恒定的 memory 要求?
No problem, just let's use a large (but constant) byte array:没问题,让我们使用一个大的(但不变的) 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;
    }    
}

As we only iterate once over the array, we have a time complexity of O(n) (where n is the number of elements in the array).由于我们只在数组上迭代一次,我们的时间复杂度为 O(n)(其中 n 是数组中元素的数量)。
And because we always use the same amount of space we have a memory complexity of O(1), that is independent of anything.因为我们总是使用相同数量的空间,所以我们有一个 O(1) 的 memory 复杂度,这与任何事情无关。

As these are int s, you could use a BitSet :由于这些是int s,您可以使用BitSet

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 : ", ""))
        );
}

Note that (as per comment) negative values need to be treated separately, as otherwise you could be faced with IndexOutOfBoundsException .请注意(根据评论)负值需要单独处理,否则您可能会遇到IndexOutOfBoundsException

Just one for loop, i will increment when j is at the end of the array, the current arr[i] is found earlier of a new duplicate element is found只有一个 for 循环,当j位于数组末尾时i将递增,当前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();
    }

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

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