Java数组去重的多种方法及其实现详解

更新时间:2024-05-17 14:09:25   人气:3764
在编程实践中,尤其是在处理数据结构时,去除重复元素是一个常见的需求。对于使用Java语言的开发者来说,在操作数组这一基础且常用的数据类型中实现去重功能有着多种策略与技巧。以下将详细介绍几种高效的 Java 数组去重的方法及其具体实现。

**1. 使用HashSet**

HashSet是基于哈希表(HashMap)的一个无序不重复集合类,插入和查询的时间复杂度均为O(1)。因此,我们可以借助于它来高效地完成数组去重的操作:

java

import java.util.HashSet;
import java.util.Arrays;

public class Main {
public static void main(String[] args) {
Integer[] array = new Integer[]{1, 2, 3, 4, 4, 5, 6, 7, 8, 9, 0, ½, 1};

HashSet<Integer> set = new HashSet<>(Arrays.asList(array));
// 转换回Array
array = set.toArray(new Integer[set.size()]);

System.out.println(Arrays.toString(array));
}
}


上述代码首先通过`Arrays.asList()`函数把原始数组转换为列表并传入HashSet构造器进行初始化以自动过滤掉重复项;然后利用 `Set#toArray(T[])` 方法再转回到一个新数组。

**2. 双指针法**

双指针对撞算法是一种空间优化的方式,可以在原址上修改数组达到去重的效果,但要求有序:

java

public class Main {
public static int removeDuplicates(int[] nums) {
if (nums.length <= 1)
return nums.length;

int left = 0; //慢指针指向未确定是否重复的位置
for (int right = 1; right < nums.length; ++right){
//快指针遍历查找不同值
if(nums[right] != nums[left]){
left++;
nums[left] = nums[right];
}
}

return left + 1;
}

public static void main(String[] args){
int [] arr = {1, 1, 2, 3, 3, 4};
removeDuplicates(arr);
System.out.println(Arrays.toString(arr).substring(1,removeDuplicates(arr)));
}
}


该方法仅适用于整型,并假设输入的是升序排列的数组,其原理在于用两个索引分别从前往后、由后往前扫描比较相邻元素,若发现不相等,则交换左侧位置并将左指针右移一位。

**3. 排序+临时变量记录上次数值**

如果对排序没有硬性条件限制的话,可以先对数组进行排序,然后再遍历时忽略连续相同的数:

java

import java.util.Arrays;

public class Main {

public static void deduplicateInPlace(Integer[] numbers) {
Arrays.sort(numbers);

int indexToRemoveAt = -1;
for (int i = 1; i < numbers.length; i++) {
if (numbers[i].equals(numbers[indexToRemoveAt])) continue;

indexToRemoveAt++;
if(indexToRemoveAt != i) {
numbers[indexToRemoveAt] = numbers[i];
}
}

while (++indexToRemoveAt < numbers.length) {
numbers[indexToRemoveAt] = null; // 清除后续多余的null或可选保留最后一个有效数字。
}
}

public static void main(String[] args) {
Integer[] numbers = new Integer[]{1, 2, 2, 3, 3, 3, 4, 5, 5};

deduplicateInPlace(numbers);
System.out.println(Arrays.stream(numbers)
.filter(num -> num!= null)
.toList());
}
}



此方案需注意:尽管实现了就地修改,但由于涉及到移动大量元素可能导致性能问题,特别是当数组较大或者包含的对象较重时更为显著。

总结起来,以上三种方式各有优劣,选择哪种取决于具体的场景以及内存/时间效率上的权衡考量。无论采取何种手段,请务必结合实际业务情景做出合理的选择。