如何在不使用 Set 的情况下有效地从数组中删除重复项

Posted

技术标签:

【中文标题】如何在不使用 Set 的情况下有效地从数组中删除重复项【英文标题】:How to efficiently remove duplicates from an array without using Set 【发布时间】:2013-07-31 18:51:29 【问题描述】:

我被要求编写自己的实现来删除数组中的重复值。这是我创建的。但经过 1,000,000 个元素的测试后,需要很长时间才能完成。我可以做些什么来改进我的算法或删除任何错误吗?

我需要编写自己的实现 - 而不是 use SetHashSet 等或任何其他工具,例如迭代器。只需一个数组即可删除重复项。

public static int[] removeDuplicates(int[] arr) 

    int end = arr.length;

    for (int i = 0; i < end; i++) 
        for (int j = i + 1; j < end; j++) 
            if (arr[i] == arr[j])                   
                int shiftLeft = j;
                for (int k = j+1; k < end; k++, shiftLeft++) 
                    arr[shiftLeft] = arr[k];
                
                end--;
                j--;
            
        
    

    int[] whitelist = new int[end];
    for(int i = 0; i < end; i++)
        whitelist[i] = arr[i];
    
    return whitelist;

【问题讨论】:

对你有什么限制?可以sort吗?您当然可以改进这个 O(n^3) 实现。该算法在最优情况下应该是 O(nln(n))。 嗯,是的,你有一个 O(n^3) 算法......这对我来说听起来不是一个好主意。 你可以使用Set&lt;Integer&gt; ? 您也在Codereview 中问过这个问题。也有an answer。 嗯,code review forum 已经有两个答案了 【参考方案1】:

你可以借助Set收藏

int end = arr.length;
Set<Integer> set = new HashSet<Integer>();

for(int i = 0; i < end; i++)
  set.add(arr[i]);

现在,如果您要遍历这个 set,它将只包含唯一值。迭代代码是这样的:

Iterator it = set.iterator();
while(it.hasNext()) 
  System.out.println(it.next());

【讨论】:

我应该为此练习编写自己的实现。不过还是谢谢。 OP 明确表示他想在没有 Set 的情况下求解。请在回答之前阅读问题。 我来这里是为了寻找一种简单易懂的方法,对我来说不管是设置还是什么都无所谓。非常感谢您的大力帮助 @goyalshub1509,当我回答时没有写他想要没有设置,所以我这样回答。【参考方案2】:

如果您被允许使用 Java 8 流:

Arrays.stream(arr).distinct().toArray();

【讨论】:

谢谢你,这很好用【参考方案3】:

注意:我假设数组已排序。

代码:

int[] input = new int[]1, 1, 3, 7, 7, 8, 9, 9, 9, 10;
int current = input[0];
boolean found = false;

for (int i = 0; i < input.length; i++) 
    if (current == input[i] && !found) 
        found = true;
     else if (current != input[i]) 
        System.out.print(" " + current);
        current = input[i];
        found = false;
    

System.out.print(" " + current);

输出:

  1 3 7 8 9 10

【讨论】:

您假设数组已排序,因此如果数组在随机位置有重复项或未排序,它将失败。 @kick Butowski 很好,如果数组已排序,则可以通过 XOR 操作更简单地完成。请参阅我的答案 假设数组已排序【参考方案4】:

通过删除最里面的 for 循环,对原始代码本身进行轻微修改。

public static int[] removeDuplicates(int[] arr)
    int end = arr.length;

    for (int i = 0; i < end; i++) 
        for (int j = i + 1; j < end; j++) 
            if (arr[i] == arr[j])                   
                /*int shiftLeft = j;
                for (int k = j+1; k < end; k++, shiftLeft++) 
                    arr[shiftLeft] = arr[k];
                */
                arr[j] = arr[end-1];
                end--;
                j--;
            
        
    

    int[] whitelist = new int[end];
    /*for(int i = 0; i < end; i++)
        whitelist[i] = arr[i];
    */
    System.arraycopy(arr, 0, whitelist, 0, end);
    return whitelist;

【讨论】:

【参考方案5】:

由于您可以假设范围在 0-1000 之间,因此有一个非常简单有效的解决方案

//Throws an exception if values are not in the range of 0-1000
public static int[] removeDuplicates(int[] arr) 
    boolean[] set = new boolean[1001]; //values must default to false
    int totalItems = 0;

    for (int i = 0; i < arr.length; ++i) 
        if (!set[arr[i]]) 
            set[arr[i]] = true;
            totalItems++;
        
    

    int[] ret = new int[totalItems];
    int c = 0;
    for (int i = 0; i < set.length; ++i) 
        if (set[i]) 
            ret[c++] = i;
        
    
    return ret;

这在线性时间 O(n) 中运行。警告:返回的数组已排序,因此如果这是非法的,则此答案无效。

【讨论】:

你的实现类似于桶排序算法。 == false== true?听说过! 吗? 为什么 == 正确?掌心 为什么我们用totalItems创建新数组,我们可以使用相同的数组来节省内存,下面是代码:int c = 0; for (int i = 0; i 【参考方案6】:
class Demo 

    public static void main(String[] args) 
    
        int a[]=3,2,1,4,2,1;
        System.out.print("Before Sorting:");
        for (int i=0;i<a.length; i++ )
        
            System.out.print(a[i]+"\t");
        
        System.out.print ("\nAfter Sorting:");
        //sorting the elements
        for(int i=0;i<a.length;i++)
        
            for(int j=i;j<a.length;j++)
            
                if(a[i]>a[j])
                
                    int temp=a[i];
                    a[i]=a[j];
                    a[j]=temp;
                

            
        

        //After sorting
        for(int i=0;i<a.length;i++)
        
            System.out.print(a[i]+"\t");
        
        System.out.print("\nAfter removing duplicates:");
        int b=0;
        a[b]=a[0];
        for(int i=0;i<a.length;i++)
        
            if (a[b]!=a[i])
            
                b++;
                a[b]=a[i];
            
        
        for (int i=0;i<=b;i++ )
        
            System.out.print(a[i]+"\t");
        
    

  OUTPUT:Before Sortng:3 2 1 4 2 1 After Sorting:1 1 2 2 3 4 
                Removing Duplicates:1 2 3 4

【讨论】:

如果你解释一下你所做的事情,这样的答案对社区会更有帮助。 高效去除重复但不高效排序:-)【参考方案7】:

这个问题有很多解决方案。

    排序方法

    您对数组进行排序并仅解析唯一项

    设置方法

    您声明了一个 HashSet,您在其中放置了所有项目,然后您只有唯一的项目。

    您创建一个布尔数组来表示所有已返回的项目(这取决于您在数组中的数据)。

如果您处理大量数据,我会选择 1. 解决方案。由于您不分配额外的内存并且排序非常快。对于小数据集,复杂度为 n^2,但对于大数据集,复杂度为 n log n。

【讨论】:

【参考方案8】:

由于这个问题仍然受到很多关注,我决定通过复制this answer from Code Review.SE来回答它:

您遵循与冒泡排序相同的理念,即 非常非常非常慢。你试过这个吗?:

使用quicksort 对无序数组进行排序。快速排序要快得多 比冒泡排序(我知道,你不是排序,而是你的算法 follow 几乎和冒泡排序一样遍历数组)。

然后开始删除重复项(重复值将在每个 其他)。在for 循环中,您可以有两个索引:sourcedestination。 (在每个循环中,您将 source 复制到 destination,除非他们 是相同的,并且都增加 1)。每次你找到一个 复制你增加源(并且不执行复制)。 @morgano

【讨论】:

您可以包含任何示例吗? @Lion 在这里检查代码 - gist.github.com/anil477/c2349420b7ebca121ef82ca30b771bcd【参考方案9】:

如果您创建两个布尔数组:1 个用于负值,1 个用于正值,并在 false 时将其全部初始化。

然后,如果您已经遍历了该值,则循环遍历输入数组并在数组中查找。 如果没有,则将其添加到输出数组并将其标记为已使用。

【讨论】:

我认为这是最好的方法......我也会尝试使用大整数而不是布尔数组(它在内存使用方面更有效,但有点难以理解,因为你将需要进行按位运算)【参考方案10】:
import java.util.Arrays;

public class Practice 

public static void main(String[] args) 
    int a[] =  1, 3, 3, 4, 2, 1, 5, 6, 7, 7, 8, 10 ;
    Arrays.sort(a);
    int j = 0;
    for (int i = 0; i < a.length - 1; i++) 
        if (a[i] != a[i + 1]) 
            a[j] = a[i];
            j++;
        
    
    a[j] = a[a.length - 1];
    for (int i = 0; i <= j; i++) 
        System.out.println(a[i]);
    



**This is the most simplest way**

【讨论】:

【参考方案11】:
package com.pari.practice;

import java.util.HashSet;
import java.util.Iterator;

import com.pari.sort.Sort;

public class RemoveDuplicates 

 /**
 * brute force- o(N square)
 * 
 * @param input
 * @return
 */
public static int[] removeDups(int[] input)
    boolean[] isSame = new boolean[input.length];
    int sameNums = 0;

    for( int i = 0; i < input.length; i++ )
        for( int j = i+1; j < input.length; j++)
            if( input[j] == input[i] ) //compare same
                isSame[j] = true;
                sameNums++;
            
        
    

    //compact the array into the result.
    int[] result = new int[input.length-sameNums];
    int count = 0;
    for( int i = 0; i < input.length; i++ )
        if( isSame[i] == true) 
            continue;
        
        else
            result[count] = input[i];
            count++;
        
    

    return result;


/**
 * set - o(N)
 * does not guarantee order of elements returned - set property
 * 
 * @param input
 * @return
 */
public static int[] removeDups1(int[] input)
    HashSet myset = new HashSet();

    for( int i = 0; i < input.length; i++ )
        myset.add(input[i]);
    

    //compact the array into the result.
    int[] result = new int[myset.size()];
    Iterator setitr = myset.iterator();
    int count = 0;
    while( setitr.hasNext() )
        result[count] = (int) setitr.next();
        count++;
    

return result;


/**
 * quicksort - o(Nlogn)
 * 
 * @param input
 * @return
 */
public static int[] removeDups2(int[] input)
    Sort st = new Sort();
    st.quickSort(input, 0, input.length-1); //input is sorted

    //compact the array into the result.
    int[] intermediateResult = new int[input.length];
    int count = 0;
    int prev = Integer.MIN_VALUE;
    for( int i = 0; i < input.length; i++ )
        if( input[i] != prev )
            intermediateResult[count] = input[i];
            count++;
        
        prev = input[i];
    

    int[] result = new int[count];
    System.arraycopy(intermediateResult, 0, result, 0, count);

    return result;



public static void printArray(int[] input)
    for( int i = 0; i < input.length; i++ )
        System.out.print(input[i] + " ");
    


public static void main(String[] args)
    int[] input = 5,6,8,0,1,2,5,9,11,0;
    RemoveDuplicates.printArray(RemoveDuplicates.removeDups(input));
    System.out.println();
    RemoveDuplicates.printArray(RemoveDuplicates.removeDups1(input));
    System.out.println();
    RemoveDuplicates.printArray(RemoveDuplicates.removeDups2(input));


输出: 5 6 8 0 1 2 9 11

0 1 2 5 6 8 9 11

0 1 2 5 6 8 9 11

我刚刚写了上面的代码来试一试。谢谢。

【讨论】:

【参考方案12】:
public static int[] removeDuplicates(int[] arr)
    HashSet<Integer> set = new HashSet<>();
    final int len = arr.length;
    //changed end to len
    for(int i = 0; i < len; i++)
        set.add(arr[i]);
    

    int[] whitelist = new int[set.size()];
    int i = 0;
    for (Iterator<Integer> it = set.iterator(); it.hasNext();) 
        whitelist[i++] = it.next();
    
    return whitelist;

在 O(N) 时间内运行,而不是 O(N^3) 时间

【讨论】:

我猜这不会保持数组的顺序。你最好使用 Set-Implementation 这样做。【参考方案13】:

更新用户输入并不是什么好玩的事,但考虑到您的限制......

public int[] removeDup(int[] nums) 
  Arrays.sort(nums);
  int x = 0;
  for (int i = 0; i < nums.length; i++) 
    if (i == 0 || nums[i] != nums[i - 1]) 
    nums[x++] = nums[i];
    
  
  return Arrays.copyOf(nums, x);

数组排序可以很容易地替换为任何 nlog(n) 算法。

【讨论】:

【参考方案14】:

这是对数组中的元素进行排序的简单方法

public class DublicatesRemove 
    public static void main(String args[]) throws Exception 

        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        System.out.println("enter size of the array");
        int l = Integer.parseInt(br.readLine());
        int[] a = new int[l];
        // insert elements in the array logic
        for (int i = 0; i < l; i++) 
        
            System.out.println("enter a element");
            int el = Integer.parseInt(br.readLine());
            a[i] = el;
        
        // sorting elements in the array logic
        for (int i = 0; i < l; i++) 
        
            for (int j = 0; j < l - 1; j++) 
            
                if (a[j] > a[j + 1])
                
                    int temp = a[j];
                    a[j] = a[j + 1];
                    a[j + 1] = temp;
                
            
        
        // remove duplicate elements logic
        int b = 0;
        a[b] = a[0];
        for (int i = 1; i < l; i++)
        
            if (a[b] != a[i])
            
                b++;
                a[b]=a[i];

            

        
        for(int i=0;i<=b;i++)
        
            System.out.println(a[i]);
        


    

【讨论】:

【参考方案15】:

对于已排序的数组,只需检查下一个索引:

//sorted data!
public static int[] distinct(int[] arr) 
    int[] temp = new int[arr.length];

    int count = 0;
    for (int i = 0; i < arr.length; i++) 
        int current = arr[i];

        if(count > 0 )
            if(temp[count - 1] == current)
                continue;

        temp[count] = current;
        count++;
    

    int[] whitelist = new int[count];
    System.arraycopy(temp, 0, whitelist, 0, count);

    return whitelist;

【讨论】:

现有代码不起作用,因为new int[] ; 是一个空数组,因此您将获得ArrayIndexOutOfBoundsException。更糟糕的是,二分搜索仅适用于排序的数据。您尚未对数据进行排序。一旦数据被排序,那么二分查找就是多余的。 其他你看不懂的,一切都好吗?我的答案底部有一条注释(所以基本上你看不懂?)+来自 ashur 的评论指出数组可以排序......所以这是垃圾邮件? ps 排序数据 = 唯一数据?在什么宇宙?唯一的其他选择是检查 index+1 项目,这是您评论中唯一有意义的部分 对不起,我想我误解了。我认为您需要将值 int[] 设置为 new int[arr.lenght] 否则代码将无法正常工作。并且您需要添加该数组必须已经排序。 OP 所说的只是你 可以 对数据进行排序,而不是它已经排序。我仍然不认为这个答案是正确的。至于sort == unqiue,那不是我说的。我只是说,如果对数据进行了排序,那么您可以在没有二进制搜索的情况下找到唯一值,因为根据定义,它们是相邻的 - 因此您不需要去寻找它们。 是的,你在二分搜索部分是正确的,但无论哪种方式,数据都需要排序......所以索引+1是最好的主意【参考方案16】:

您需要对数组进行排序,然后循环并删除重复项。由于您无法使用其他工具,因此您需要自己编写代码。

您可以轻松找到 Java on the internet 中的快速排序示例(本示例基于该示例)。

public static void main(String[] args) throws Exception 
    final int[] original = new int[]1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1;
    System.out.println(Arrays.toString(original));
    quicksort(original);
    System.out.println(Arrays.toString(original));
    final int[] unqiue = new int[original.length];
    int prev = original[0];
    unqiue[0] = prev;
    int count = 1;
    for (int i = 1; i < original.length; ++i) 
        if (original[i] != prev) 
            unqiue[count++] = original[i];
        
        prev = original[i];
    
    System.out.println(Arrays.toString(unqiue));
    final int[] compressed = new int[count];
    System.arraycopy(unqiue, 0, compressed, 0, count);
    System.out.println(Arrays.toString(compressed));


private static void quicksort(final int[] values) 
    if (values.length == 0) 
        return;
    
    quicksort(values, 0, values.length - 1);


private static void quicksort(final int[] values, final int low, final int high) 
    int i = low, j = high;
    int pivot = values[low + (high - low) / 2];
    while (i <= j) 
        while (values[i] < pivot) 
            i++;
        
        while (values[j] > pivot) 
            j--;
        
        if (i <= j) 
            swap(values, i, j);
            i++;
            j--;
        
    
    if (low < j) 
        quicksort(values, low, j);
    
    if (i < high) 
        quicksort(values, i, high);
    


private static void swap(final int[] values, final int i, final int j) 
    final int temp = values[i];
    values[i] = values[j];
    values[j] = temp;

所以这个过程分 3 步运行。

    对数组进行排序 - O(nlgn) 删除重复项 - O(n) 压缩数组 - O(n)

因此,这大大改善了您的 O(n^3) 方法。

输出:

[1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1]
[1, 1, 1, 2, 4, 4, 7, 8, 8, 9, 9]
[1, 2, 4, 7, 8, 9, 0, 0, 0, 0, 0]
[1, 2, 4, 7, 8, 9]

编辑

OP 声明 数组中的值并不重要。但我可以假设范围在 0-1000 之间。这是一个可以使用 O(n) 排序的经典案例。

我们创建一个大小为range +1 的数组,在本例中为1001。然后我们循环数据并增加与数据点对应的每个索引上的值。

然后我们可以压缩结果数组,删除没有增加的值。这使得值是唯一的,因为我们忽略了计数。

public static void main(String[] args) throws Exception 
    final int[] original = new int[]1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1, 1000, 1000;
    System.out.println(Arrays.toString(original));
    final int[] buckets = new int[1001];
    for (final int i : original) 
        buckets[i]++;
    
    final int[] unique = new int[original.length];
    int count = 0;
    for (int i = 0; i < buckets.length; ++i) 
        if (buckets[i] > 0) 
            unique[count++] = i;
        
    
    final int[] compressed = new int[count];
    System.arraycopy(unique, 0, compressed, 0, count);
    System.out.println(Arrays.toString(compressed));

输出:

[1, 1, 2, 8, 9, 8, 4, 7, 4, 9, 1, 1000, 1000]
[1, 2, 4, 7, 8, 9, 1000]

【讨论】:

坏主意...为什么要找到最大值?您需要遍历所有值吗?就像我之前在评论中所说的那样,对其进行排序并检查 index+1 项 @mc_fish OP 说明了值的范围。这就是为什么我提出了两种方法。一个如果范围未知,一个如果范围是已知small 是的,但他以 1M 的速度运行测试?只是说 是的,1M 值,但引用他的评论,假设范围在 0-1000 之间。所以范围很小。【参考方案17】:
public static void main(String args[]) 
    int[] intarray = 1,2,3,4,5,1,2,3,4,5,1,2,3,4,5;

    Set<Integer> set = new HashSet<Integer>();
    for(int i : intarray) 
        set.add(i);
    

    Iterator<Integer> setitr = set.iterator();
    for(int pos=0; pos < intarray.length; pos ++) 
        if(pos < set.size()) 
            intarray[pos] =setitr.next();
         else 
            intarray[pos]= 0;
        
    

    for(int i: intarray)
    System.out.println(i);

【讨论】:

这个程序的输出是:1 2 3 4 5 0 0 0 0 0 0 0 0 0 0【参考方案18】:

我知道这有点死,但我只是写这个供我自己使用。它或多或少与添加到哈希集然后从其中提取所有元素相同。它应该在 O(nlogn) 最坏的情况下运行。

    public static int[] removeDuplicates(int[] numbers) 
    Entry[] entries = new Entry[numbers.length];
    int size = 0;
    for (int i = 0 ; i < numbers.length ; i++) 
        int nextVal = numbers[i];
        int index = nextVal % entries.length;
        Entry e = entries[index];
        if (e == null) 
            entries[index] = new Entry(nextVal);
            size++;
         else 
            if(e.insert(nextVal)) 
                size++;
            
        
    
    int[] result = new int[size];
    int index = 0;
    for (int i = 0 ; i < entries.length ; i++) 
        Entry current = entries[i];
        while (current != null) 
            result[i++] = current.value;
            current = current.next;
        
    
    return result;


public static class Entry 
    int value;
    Entry next;

    Entry(int value) 
        this.value = value;
    

    public boolean insert(int newVal) 
        Entry current = this;
        Entry prev = null;
        while (current != null) 
            if (current.value == newVal) 
                return false;
             else if(current.next != null) 
                prev = current;
                current = next;
            
        
        prev.next = new Entry(value);
        return true;
    

【讨论】:

【参考方案19】:
int tempvar=0; //Variable for the final array without any duplicates
     int whilecount=0;    //variable for while loop
     while(whilecount<(nsprtable*2)-1) //nsprtable can be any number
     
//to check whether the next value is idential in case of sorted array       
if(temparray[whilecount]!=temparray[whilecount+1])
        
            finalarray[tempvar]=temparray[whilecount];
            tempvar++;
            whilecount=whilecount+1;
        
        else if (temparray[whilecount]==temparray[whilecount+1])
        
            finalarray[tempvar]=temparray[whilecount];
            tempvar++;
            whilecount=whilecount+2;
        
     

希望这有助于或解决目的。

【讨论】:

【参考方案20】:
 package javaa;

public class UniqueElementinAnArray 


 public static void main(String[] args) 
 
    int[] a = 10,10,10,10,10,100;
    int[] output = new int[a.length];
    int count = 0;
    int num = 0;

    //Iterate over an array
    for(int i=0; i<a.length; i++)
    
        num=a[i];
        boolean flag = check(output,num);
        if(flag==false)
        
            output[count]=num;
            ++count;
        

    

    //print the all the elements from an array except zero's (0)
    for (int i : output) 
    
        if(i!=0 )
            System.out.print(i+"  ");
    



/***
 * If a next number from an array is already exists in unique array then return true else false
 * @param arr   Unique number array. Initially this array is an empty.
 * @param num   Number to be search in unique array. Whether it is duplicate or unique.
 * @return  true: If a number is already exists in an array else false 
 */
public static boolean check(int[] arr, int num)

    boolean flag = false;
    for(int i=0;i<arr.length; i++)
    
        if(arr[i]==num)
        
            flag = true;
            break;
        
    
    return flag;

【讨论】:

【参考方案21】:
public static int[] removeDuplicates(int[] arr) 

int end = arr.length;

 HashSet<Integer> set = new HashSet<Integer>(end);
    for(int i = 0 ; i < end ; i++)
        set.add(arr[i]);
    
return set.toArray();

【讨论】:

【参考方案22】:

你可以使用一个辅助数组(temp),它的索引是主数组的数字。所以时间复杂度将是线性和 O(n)。由于我们想在不使用任何库的情况下做到这一点,我们定义了另一个数组(唯一的)来推送非重复元素:

var num = [2,4,9,4,1,2,24,12,4];
let temp = [];
let unique = [];
let j = 0;
for (let i = 0; i < num.length; i++)
  if (temp[num[i]] !== 1)
    temp[num[i]] = 1;
    unique[j++] = num[i];
  

console.log(unique);

【讨论】:

【参考方案23】:

如果您希望使用相同的数组删除重复项并保持 O(n) 的时间复杂度。那么这应该可以解决问题。此外,仅当数组已排序时才有效。

function removeDuplicates_sorted(arr)

let j = 0; 

for(let x = 0; x < arr.length - 1; x++)
    
    if(arr[x] != arr[x + 1]) 
        arr[j++] = arr[x];
    


arr[j++] = arr[arr.length - 1];
arr.length = j;

return arr;

这里是一个未排序的数组,它的 O(n) 但比排序的使用更多的空间复杂度。

function removeDuplicates_unsorted(arr)

let map = ;
let j = 0;

for(var numbers of arr)
    if(!map[numbers])
        map[numbers] = 1;
        arr[j++] = numbers;
    


arr.length = j;

return arr;

【讨论】:

【参考方案24】:
public static void main(String[] args) 
        Integer[] intArray =  1, 1, 1, 2, 4, 2, 3, 5, 3, 6, 7, 3, 4, 5 ;
        Integer[] finalArray = removeDuplicates(intArray);
        System.err.println(Arrays.asList(finalArray));
    

    private static Integer[] removeDuplicates(Integer[] intArray) 
        int count = 0;
        Integer[] interimArray = new Integer[intArray.length];
        for (int i = 0; i < intArray.length; i++) 
            boolean exists = false;
            for (int j = 0; j < interimArray.length; j++) 
                if (interimArray[j]!=null && interimArray[j] == intArray[i]) 
                    exists = true;
                
            
            if (!exists) 
                interimArray[count] = intArray[i];
                count++;
            
        
        final Integer[] finalArray = new Integer[count];
        System.arraycopy(interimArray, 0, finalArray, 0, count);
        return finalArray;
    

【讨论】:

【参考方案25】:

我觉得 android Killer 的想法很棒,但我只是想知道我们是否可以利用 HashMap。所以我做了一个小实验。而且我发现 HashMap 似乎比 HashSet 快。

代码如下:

    int[] input = new int[1000000];

    for (int i = 0; i < input.length; i++) 
        Random random = new Random();
        input[i] = random.nextInt(200000);
    

    long startTime1 = new Date().getTime();
    System.out.println("Set start time:" + startTime1);

    Set<Integer> resultSet = new HashSet<Integer>();

    for (int i = 0; i < input.length; i++) 
        resultSet.add(input[i]);
    

    long endTime1 = new Date().getTime();
    System.out.println("Set end time:"+ endTime1);
    System.out.println("result of set:" + (endTime1 - startTime1));     
    System.out.println("number of Set:" + resultSet.size() + "\n");

    long startTime2 = new Date().getTime();
    System.out.println("Map start time:" + startTime1);

    Map<Integer, Integer> resultMap = new HashMap<Integer, Integer>();

    for (int i = 0; i < input.length; i++) 
        if (!resultMap.containsKey(input[i]))
            resultMap.put(input[i], input[i]);
    

    long endTime2 = new Date().getTime();
    System.out.println("Map end Time:" + endTime2);
    System.out.println("result of Map:" + (endTime2 - startTime2));
    System.out.println("number of Map:" + resultMap.size());

结果如下:

Set start time:1441960583837
Set end time:1441960583917
result of set:80
number of Set:198652

Map start time:1441960583837
Map end Time:1441960583983
result of Map:66
number of Map:198652

【讨论】:

【参考方案26】:

这里没有使用 Set、Map、List 或任何额外的集合,只有两个数组:

package arrays.duplicates;

import java.lang.reflect.Array;
import java.util.Arrays;

public class ArrayDuplicatesRemover<T> 

    public static <T> T[] removeDuplicates(T[] input, Class<T> clazz) 
        T[] output = (T[]) Array.newInstance(clazz, 0);
        for (T t : input) 
            if (!inArray(t, output)) 
                output = Arrays.copyOf(output, output.length + 1);
                output[output.length - 1] = t;
            
        
        return output;
    

    private static <T> boolean inArray(T search, T[] array) 
        for (T element : array) 
            if (element.equals(search)) 
                return true;
            
        
        return false;
    


主要测试一下

package arrays.duplicates;

import java.util.Arrays;

public class TestArrayDuplicates 

    public static void main(String[] args) 
        Integer[] array = 1, 1, 2, 2, 3, 3, 3, 3, 4;
        testArrayDuplicatesRemover(array);
    

    private static void testArrayDuplicatesRemover(Integer[] array) 
        final Integer[] expectedResult = 1, 2, 3, 4;
        Integer[] arrayWithoutDuplicates = ArrayDuplicatesRemover.removeDuplicates(array, Integer.class);
        System.out.println("Array without duplicates is supposed to be: " + Arrays.toString(expectedResult));
        System.out.println("Array without duplicates currently is: " + Arrays.toString(arrayWithoutDuplicates));
        System.out.println("Is test passed ok?: " + (Arrays.equals(arrayWithoutDuplicates, expectedResult) ? "YES" : "NO"));
    


还有输出:

Array without duplicates is supposed to be: [1, 2, 3, 4]
Array without duplicates currently is: [1, 2, 3, 4]
Is test passed ok?: YES

【讨论】:

【参考方案27】:

这个怎么样,只用于数字的排序数组,打印没有重复的数组,不使用Set或其他集合,只是数组:

 public static int[] removeDuplicates(int[] array) 
    int[] nums =new int[array.length];
    int addedNum = 0;
    int j=0;
    for(int i=0;i<array.length;i++) 
        if (addedNum != array[i]) 
        nums[j] = array[i];
        j++;
        addedNum = nums[j-1];
        
    
    return Arrays.copyOf(nums, j);

在 33020 纳秒(0.033020 毫秒)内处理的 1040 个重复数字的数组。

【讨论】:

优秀的解决方案,除了一点小改动。请将 array.length 移到 for 循环之外。【参考方案28】:

好的,所以你不能使用Set 或其他集合。到目前为止我在这里没有看到的一种解决方案是基于使用 Bloom filter 的解决方案,它本质上是一个位数组,所以也许这可以满足您的要求。

布隆过滤器是一种可爱且非常方便的技术,快速且节省空间,可用于快速检查集合中元素的存在,而无需存储集合本身或元素。它的误报率(通常很小),但没有误报率。换句话说,对于您的问题,如果 Bloom 过滤器告诉您到目前为止还没有看到某个元素,那么您可以确定它没有。但是如果它说一个元素已经被看到,你实际上需要检查。如果您的列表中没有太多重复项,这仍然可以节省大量时间(对于那些,没有循环可做,除非在误报的小概率情况下 - 您通常根据多少来选择此比率您愿意为 Bloom 过滤器提供的空间(经验法则:每个唯一元素少于 10 位,误报率为 1%)。

布隆过滤器有很多实现,参见例如here 或 here,所以我不会在这个答案中重复。让我们假设最后一个参考中描述的 api,特别是 put(E e) 的 description:

true 如果 Bloom 过滤器的位由于此操作而改变。如果位发生变化,这肯定是第一次将对象添加到过滤器中。如果这些位没有改变,这可能是第一次将对象添加到过滤器中。 (...)

使用这种布隆过滤器的实现将是:

public static int[] removeDuplicates(int[] arr) 
    ArrayList<Integer> out = new ArrayList<>();
    int n = arr.length;
    BloomFilter<Integer> bf = new BloomFilter<>(...);  // decide how many bits and how many hash functions to use (compromise between space and false positive rate)

    for (int e : arr) 
        boolean might_contain = !bf.put(e);
        boolean found = false;
        if (might_contain) 
            // check if false positive
            for (int u : out) 
                if (u == e) 
                    found = true;
                    break;
                
            
        
        if (!found) 
            out.add(e);
        
    
    return out.stream().mapToInt(i -> i).toArray();

显然,如果您可以就地更改传入数组,则不需要ArrayList:最后,当您知道唯一元素的实际数量时,只需arraycopy() 那些。

【讨论】:

【参考方案29】:

为什么不是所有人都检查下面几行?

我需要编写自己的实现 - 不要使用 Set、HashSet 等或任何其他工具,例如迭代器。只需一个数组即可删除重复项。

我发布了非常简单的实现,关心上面的行。

public class RemoveDuplicates 

public static void main(String[] args) 

    int[] arr =  1, 2, 3, 4, 2, 3, 1 ; // input array
    int len = arr.length;
    for (int i = 0; i < arr.length; i++) 
        for (int j = i + 1; j < len; j++) 
            if (arr[i] == arr[j]) 
                while (j < (len) - 1) 
                    arr[j] = arr[j - 1];
                    j++;
                
                len--;
            
        
    
    for (int i = 0; i < len; i++) 
        System.out.print("  " +arr[i]);
    

   
 

输入:1、2、3、4、2、3、1

输出:1 2 3 4

【讨论】:

您的解决方案是 O(n^2),这可以进一步改进,因为这里有人已经在 cmets 中提到过。如果您使用快速排序,则平均情况复杂度为 O(nlogn)(合并排序也适用)来对数组进行排序。接下来,您可以遍历排序数组一次以替换 O(n) 中的所有重复项。所以总体复杂度是 O(nlogn)。 我已经按问题回答了 错误的程序试试这个: -- int[] arr = 1,2,3,4,2,3,1,1,11,6,1; // 输入数组 1 2 3 4 4 4 //输出【参考方案30】:

这是我的解决方案。时间复杂度为o(n^2)

public String removeDuplicates(char[] arr) 
        StringBuilder sb = new StringBuilder();

        if (arr == null)
            return null;
        int len = arr.length;

        if (arr.length < 2)
            return sb.append(arr[0]).toString();

        for (int i = 0; i < len; i++) 

            for (int j = i + 1; j < len; j++) 
                if (arr[i] == arr[j]) 
                    arr[j] = 0;

                
            
            if (arr[i] != 0)
                sb.append(arr[i]);
        

        return sb.toString().trim();
    

【讨论】:

以上是关于如何在不使用 Set 的情况下有效地从数组中删除重复项的主要内容,如果未能解决你的问题,请参考以下文章

如何在不使用重命名命令的情况下递归搜索目录并从文件名中删除开/关括号? [复制]

如何在不使用 cytoscape.js 重绘图形的情况下删除特定边?

Flutter:如何在不阻塞 UI 的情况下异步地从资产中读取文件

如何有效地从另一个字符串中找到的字符串中删除重复字符?

如何在不删除或移动mysql中的表的情况下重命名数据库? [复制]

如何在不转换为json的情况下将C#数组用于javascript数组?