在不使用Sets的情况下从数组中删除重复项而不会干扰元素的顺序

时间:2015-06-23 09:54:52

标签: java

我需要一个java代码,可以在不改变元素顺序的情况下从数组中删除重复项,而无需使用Sets或排序技术。

例如: 如果输入数组是{23,1,5,4,2,23,6,2,4} 然后输出应为{23,1,5,4,2,6}

6 个答案:

答案 0 :(得分:3)

您可以在O(n^2)时间内使用 O(1)额外空格进行此操作。

public static int[] noSpaceElementDistinctness(int[] arr) {
    int n = arr.length;
    for (int i = 0; i < n;i++) {
        boolean exists = false;
        for (int j = 0; j < i; j++) {
            if (arr[i] == arr[j]) {
                exists = true;
                break;
            }
        }
        if (exists) {
            for (int j = i+1; j<n; j++)
                arr[j-1] = arr[j];
        n--;
        i--; //to iterate the next element, which is now at index i, not i+1.
        }
    }
    for (int i = n; i < arr.length; i++) arr[i] = Integer.MIN_VALUE; //indicates no value
    return arr;

}

作为旁注,元素清晰度问题并不像从第一眼看起来那样有效地解决,而且它是一个严格的下限,你可以采取哪些措施来有效地解决它。 This thread讨论了它。

答案 1 :(得分:1)

如果你使用Java 8,一个简单的方法是:

int[] array = {23, 1, 5, 4, 2, 23, 6, 2, 4};
int[] noDupes = IntStream.of(array).distinct().toArray();
System.out.println(Arrays.toString(noDupes)); // [23, 1, 5, 4, 2, 6]

答案 2 :(得分:0)

创建一个新的ArrayList()。循环遍历旧列表并将值复制到new,除非它已经在其中。

订单将被更改,因为您不会复制所有...

答案 3 :(得分:0)

有几个选项 - 一些比其他选项更有效:

/**
 * Brute force approach - very inefficient.
 *
 * Finds each duplicate and removes it.
 */
private int[] removeDupesUsingNoExtraMemory(int[] a) {
    int length = a.length;
    for (int i = 0; i < length - 1; i++) {
        for (int j = i + 1; j < length; j++) {
            if (a[i] == a[j]) {
                // No point copying if this is the last one.
                if (j < length - 1) {
                    // Remove a[j].
                    System.arraycopy(a, j + 1, a, j, length - j - 1);
                }
                length -= 1;
            }
        }
    }
    // Actually it does use extra memory but only to trim the array because Java cannot slice arrays.
    return Arrays.copyOf(a, length);
}

/**
 * A bit more efficient.
 *
 * Copies only non-duplicate ones.
 */
private int[] removeDupesDifferently(int[] a) {
    int length = a.length;
    // Copying to the end backwards.
    int to = length - 1;
    // Copy backwards so we remove the second duplicate - not the first.
    for (int i = length - 1; i >= 0; i--) {
        boolean duplicate = false;
        for (int j = 0; j < i && !duplicate; j++) {
            duplicate |= a[i] == a[j];
        }
        if (!duplicate) {
            a[to--] = a[i];
        }
    }
    return Arrays.copyOfRange(a, to + 1, a.length);
}

/**
 * Most efficient - but uses a `Set`.
 *
 * Builds a `Set` of `seen` values so we don't copy duplicates.
 */
private int[] removeDupesUsingASet(int[] a) {
    int to = 0;
    Set<Integer> seen = new HashSet<>();
    for (int i = 0; i < a.length - 1; i++) {
        // Seen it before?
        if (!seen.contains(a[i])) {
            a[to++] = a[i];
            // Seen that one - don't want to see it again.
            seen.add(a[i]);
        }
    }
    return Arrays.copyOf(a, to);
}

public void test() {
    System.out.println("removeDupesUsingNoExtraMemory = " + Arrays.toString(removeDupesUsingNoExtraMemory(new int[]{23, 1, 5, 4, 2, 23, 6, 2, 4})));
    System.out.println("removeDupesDifferently = " + Arrays.toString(removeDupesDifferently(new int[]{23, 1, 5, 4, 2, 23, 6, 2, 4})));
    System.out.println("removeDupesUsingASet = " + Arrays.toString(removeDupesUsingASet(new int[]{23, 1, 5, 4, 2, 23, 6, 2, 4})));
}

答案 4 :(得分:0)

    int arr[] = {23,1,5,4,2,6} ;
    List<Integer> list = new ArrayList<Integer>();
    for(int i = 0; i<arr.length; i++) {
        if (!list.contains(arr[i])) {
            list.add(arr[i]);
        }
    }

    Iterator it = list.iterator();
    while(it.hasNext()){
        System.out.println(it.next());
    }

答案 5 :(得分:0)

如果您只需要在不修改阵列的情况下打印唯一元素,则可以使用此替代解决方案。使用O(n log n)对数组进行排序(例如,合并排序)并运行数组O(n)以仅打印其相邻元素不同的元素,即:

if( arr[i] != arr[i + 1]) {
  print(arr[i]);
}

干杯!