我们在刷 leetcode 时候经常会遇到数组去重的问题,当然我这里说的数组去重也包括 String 字符串去重,因为 String 可以 toCharArray 嘛。那我们怎么做呢?什么样的场景需要用何种方式呢?怎么做才最高效呢?带着这些疑问,我们来看看下面的 7 种实现方式,以及适用场景和特点介绍吧!
特点:简单直接,但是去重后无序,既不是输入的顺序,也不是从小到大的排序
因此我们遇到仅仅是去重的场景,可以考虑到使用 HashSet 去重的方式了
public int[] unique(int[] arr) {
Set<Integer> set = new HashSet<>(Arrays.asList(arr));
int[] result = new int[set.size()];
int i = 0;
for (int a : set) {
result[i++] = a;
}
return result;
}
你要是写成下面常规写法当然也可以,注意这只是写法不同,形式还是一样的用 HashSet 去重
public int[] unique(int[] arr) {
Set<Integer> set = new HashSet<>();
for (int a : arr) {
set.add();
}
int[] result = new int[set.size()];
Iterator it = set.iterator();
int i = 0;
while (it.hasNext()) {
result[i++] = (int)it.next();
}
return result;
}
特点:简单直接,去重后的循环和输入的循序不一致,但是可以自动排好序,默认从小到大
因此,当我们遇到去重后需要从小到大排好序,就可以考虑到使用 TreeSet 去重了
public int[] unique(int[] arr) {
Set<Integer> set = new TreeSet<>(Arrays.asList(arr));
int[] result = new int[set.size()];
int i = 0;
for (int a : set) {
result[i++] = a;
}
return result;
}
特点:简单直接,去重后的循序和输入的顺序一致,但是不是排好序的
因此对于需要保持数组原有顺序不变,就可以考虑到用 LinkedHashSet 来做了
public int[] unique(int[] arr) {
Set<Integer> set = new LinkedHashSet<>(Arrays.asList(arr));
int[] result = new int[set.size()];
int i = 0;
for (int a : set) {
result[i++] = a;
}
return result;
}
特点:很容易理解,去重后和输入的顺序保持一致,是稳定的,但是最后若是输出数组,还要多出一个循环
public int[] unique(int[] arr) {
List<Integer> list = new ArrayList<>();
for (int a : arr) {
if (!list.contains(a)) {
list.add(a);
}
}
int[] result = new int[list.size()];
int i = 0;
for (int a : list) {
result[i++] = a;
}
return result;
}
特点:比较麻烦,基本不会去这么写
这里的思路是两层循环遍历,里面这层循环是遍历前面和当前有没有相当,即重复的元素
public int[] unique(int[] arr) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
int j = 0;
for (; j < i; j++) {
if (arr[i] == arr[j]) {
break;
}
}
if (j == i) {
list.add(arr[i]);
}
}
int[] result = new int[list.size()];
int i = 0;
for (int a : list) {
result[i++] = a;
}
return result;
}
特点:还是比较麻烦,基本不会这么去用
这里的思路是两层循环,里面的这层循环遍历的次数少了,只遍历去重了的前面的数字
public int[] unqiue(int[] arr) {
List<Integer> list = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
int j = 0;
for (; j < list.size(); j++) {
if (arr[i] == list.get(j)) {
break;
}
}
if (j == list.size()) {
list.add(arr[i]);
}
}
int[] result = new int[list.size()];
int i = 0;
for (int a : list) {
result[i++] = a;
}
return result;
}
特点:高效,写起来可能稍微麻烦些,占用空间较大,输出与输入顺序一致,且稳定
public int[] unique(int[] arr) {
Map<Integer, Integer> map = new HashMap<>();
List<Integer> list = new ArrayList<>();
for (int i = 0; i < arr.length; i++) {
if (map.get(arr[i]) == null) {
list.add(arr[i]);
map.put(arr[i], i);
}
}
int[] result = new int[list.size()];
int i = 0;
for (int a : list) {
result[i++] = a;
}
return result;
}
对于 String 类型数据,我建议转成 char[] 来做,这样要快一些,若直接使用 String 的话也能做,可以考虑 indexOf() 方法和 contains() 方法,前者若子串存在返回第一个的下标,第二个则是返回布尔值,二者本质还是里头套着 for 循环去遍历元素看找不找的到