leetcode奇技淫巧-数组七种去重技巧

文章目录

    • 写在前面
    • 使用 Set 集合去重
      • 方式一:使用 HashSet 去重
      • 方式二:使用 TreeSet 去重
      • 方式三:使用 LinkedHashSet 去重
    • 使用 List.contains() 方法
      • 方式四:使用 ArrayList.contains()
    • 两层循环暴力法
      • 方式五:两层循环遍历
      • 方式六:两层循环遍历改进
    • 使用哈希表
      • 方式七:哈希表存储
    • 额外的方法
      • String 的处理

写在前面

我们在刷 leetcode 时候经常会遇到数组去重的问题,当然我这里说的数组去重也包括 String 字符串去重,因为 String 可以 toCharArray 嘛。那我们怎么做呢?什么样的场景需要用何种方式呢?怎么做才最高效呢?带着这些疑问,我们来看看下面的 7 种实现方式,以及适用场景和特点介绍吧!

使用 Set 集合去重

方式一:使用 HashSet 去重

特点:简单直接,但是去重后无序,既不是输入的顺序,也不是从小到大的排序

因此我们遇到仅仅是去重的场景,可以考虑到使用 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 去重

特点:简单直接,去重后的循环和输入的循序不一致,但是可以自动排好序,默认从小到大

因此,当我们遇到去重后需要从小到大排好序,就可以考虑到使用 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 去重

特点:简单直接,去重后的循序和输入的顺序一致,但是不是排好序的

因此对于需要保持数组原有顺序不变,就可以考虑到用 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;
}

使用 List.contains() 方法

方式四:使用 ArrayList.contains()

特点:很容易理解,去重后和输入的顺序保持一致,是稳定的,但是最后若是输出数组,还要多出一个循环

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 的处理

对于 String 类型数据,我建议转成 char[] 来做,这样要快一些,若直接使用 String 的话也能做,可以考虑 indexOf() 方法和 contains() 方法,前者若子串存在返回第一个的下标,第二个则是返回布尔值,二者本质还是里头套着 for 循环去遍历元素看找不找的到

你可能感兴趣的:(#,LeetCode,奇技淫巧)