如何在Java中删除数组中的重复元素?

390 阅读6分钟

这是常见的技术面试问题之一,会问到初级程序员和软件工程师。在Java中,如何从数组中删除重复的内容也有很多变种,比如有时数组是排序的,有时是不排序的,或者是不排序的。有时,面试官会把一半以上的时间花在这个问题上,通过施加新的限制条件,如就地删除重复的元素或不使用任何额外的数据结构等,逐步增加难度。

Btw,如果你被允许使用Java的集合框架,那么这个问题就很容易解决。不过,如果你不被允许使用SetIterator和其他Java实用类,那么它就突然变成了一个棘手的算法问题。

总之,在谈论解决方案之前,让我们先了解一下这个问题。你给了一个未经排序的整数数组,你必须从其中删除所有重复的部分。

例如,如果输入数组是{22, 3, 22, 11, 24, 24, 4, 3},那么输出数组应该是{22, 3, 11, 24, 4},即必须从原数组中删除重复的元素22, 24和3。

我相信一开始他会让你解决这个问题,而不去管原来的顺序,但根据你的表现,他可能会要求你再做一次,但这次要保持原来的顺序。让我们看看解决这个问题的不同方法。

如何在Java中从未排序的数组中删除重复的内容

删除重复元素的第一种最简单的方法是在O(nlogn) 时间内使用QuickSortMergeSort对数组进行排序,然后在O(n)时间内删除重复元素。对数组进行排序的一个好处是,重复的元素会聚集在一起,这样就很容易将它们删除。

顺便说一下,如果面试官提出一些限制条件,比如你不能对数组进行排序,或者在输出数组中必须保留元素的原始顺序,那么这个解决方案将无法工作。在这种情况下,我们需要

另一种从整数数组中删除重复的方法是使用二叉树。你可以使用数组中的数字构建一个二进制搜索树,并丢弃所有重复的数字。二进制树将只包含非重复的数值,你可以随后将其转换为数组。

然而,这个解决方案的缺点是,元素的原始顺序没有被保留下来。这个解决方案的时间复杂度是O(nLogn),因为在二叉树中插入一个节点需要O(LogN)的时间,而我们需要添加n个节点,其中n是数组的大小。

How to Remove Duplicates from Unsorted Array in Java

从未经排序的数组中删除重复内容的Java程序

现在让我们看看一个纯Java的解决方案,在这里你被允许使用Set接口。你通过使用HashSetLinkedHashSet来解决这个问题。如果你被要求保留元素的顺序,那么你可以使用LinkedHashSet,因为它可以保持元素被添加到其中的顺序。

package tool;

import static org.junit.Assert.assertArrayEquals;

import java.util.HashSet;
import java.util.Set;

import org.junit.Test;

public class DuplicateArray {

  private Integer[] removeDuplicates(Integer[] input) {
    if (input == null || input.length <= 0) {
      return input;
    }

    Set<Integer> aSet = new HashSet<>(input.length);

    // set will reject all duplicates
    for (int i : input) {
      aSet.add(i);
    }

    return aSet.toArray(new Integer[aSet.size()]);
  }

  @Test
  public void testArrayWithDuplicates() {
    Integer[] given = new Integer[] { 1, 2, 3, 3 };
    Integer[] actual = removeDuplicates(given);
    Integer[] expected = new Integer[] { 1, 2, 3 };
    assertArrayEquals(expected, actual);
  }

  @Test
  public void testArrayWithoutDuplicates() {
    Integer[] given = new Integer[] { 1, 2, 3 };
    Integer[] actual = removeDuplicates(given);
    Integer[] expected = new Integer[] { 1, 2, 3 };
    assertArrayEquals(expected, actual);
  }

  @Test
  public void testWithEmptyArray() {
    Integer[] given = new Integer[] {};
    Integer[] actual = removeDuplicates(given);
    Integer[] expected = new Integer[] {};
    assertArrayEquals(expected, actual);
  }

  @Test
  public void testWithNull() {
    Integer[] given = null;
    Integer[] actual = removeDuplicates(given);
    Integer[] expected = null;
    assertArrayEquals(expected, actual);
  }

  @Test
  public void testArrayWithAllDuplicates() {
    Integer[] given = new Integer[] { 3, 3, 3 };
    Integer[] actual = removeDuplicates(given);
    Integer[] expected = new Integer[] { 3 };
    assertArrayEquals(expected, actual);
  }

  @Test
  public void testArrayWithMultipleDuplicates() {
    Integer[] given = new Integer[] { 1, 2, 3, 3, 4, 4, 5, 5, 5 };
    Integer[] actual = removeDuplicates(given);
    Integer[] expected = new Integer[] { 1, 2, 3, 4, 5 };
    assertArrayEquals(expected, actual);
  }

}

当你在Eclipse中以JUnit测试的形式运行这个程序时,你会看到如下的绿色条,这表明所有的测试用例都通过了,我们的解决方案工作正常。

How to Remove Duplicates from Unsorted Array in Java

这是一个很好的解决方案,也说明了智能使用数据结构可以使解决方案变得简单。这段代码简单易懂,而且在CPU时间方面也非常高效,因为你只需要O(n)时间就能解决这个问题。

Btw,如果面试官仍然提出另一个约束条件,要求你在不使用Java Collection API的情况下删除重复的内容,那么你别无选择,只能在数组上进行迭代,比较每一个元素,找到并删除重复的内容。 这里讨论了完整的解决方案,你也可以在尝试后看到。

以上就是关于如何在Java中从一个未排序的数组中删除重复的元素的全部内容。每个解决方案都是可以接受的,但都有其优点和缺点。最关键的是,你应该从时间和空间复杂度最高的方案开始,然后达到最高效的方案。这是我在面试中经常使用的技巧之一,把面试官带到我的强项上。

其他阵列编码问题练习
如果你对解决更多基于阵列的算法问题感兴趣,那么这里有一些面试中经常被问到的编码问题。

  • 如何在一个整数数组上找到总和等于给定数的所有配对?[解决方案]

  • 写一个程序,从一个整数数组中找出前两个数字?[解决方案]

  • 30+ 面试中基于数组的编码问题(问题)

  • 100+破解编程面试的编码问题(问题)

  • 如何在Java中检查一个数组是否包含一个数字?[解决方案]

  • 如何在原地删除数组中的重复部分?[解决方案]

  • 如何解决Java中的二和问题?[解决方法)

  • 如何在Java中从一个给定的数组中找出最大和最小的数字?[解决方法]

  • 书评 - Grokking Algorithms(评论)

  • 为程序员提供的10个免费数据结构和算法课程[课程]。

  • 写一个程序来寻找1到100的整数数组中缺少的数字?[解决方案]

  • 在Java中如何将一个数组原地倒转?[解决方案]

  • 如何查找未排序数组中的最大和最小数?[解决方案]

  • 破解编码面试的10门算法课程[课程]。

  • 如何使用QuickSort算法对数组进行原地排序?[解决方案]

  • 如何在Java中打印数组中所有重复的元素?[解决方案]

  • 50+面试中的数据结构和算法编码问题(问题)

  • 每个程序员都应该阅读的10本算法书籍[书籍]

谢谢你阅读这篇文章。如果你喜欢这个面试问题,那么请与你的朋友和同事分享它。如果你有任何疑问或反馈,那么请留言。