大厂校招真实题目:List去重你能想到几种?

611 阅读3分钟

前言

在技术面试中,尤其是大厂的校招面试,经常会遇到一些看似简单但实际上考察面试者编程思维和基础知识的问题。本文将详细介绍如何使用多种方法对Java中的List进行去重,这些方法不仅涵盖了基础的循环遍历,还包括了更高级的集合操作和流式处理,此面试题也是本人朋友去大厂面试收集,大家如果有遇到哪些面试题也可以在评论区留言。

1. 基础方法:for循环遍历判断

最简单直接的方法是使用for循环遍历List,检查每个元素是否已经存在于新的List中。如果不存在,则将其添加到新的List中。这种方法虽然简单,但在处理大数据量时效率较低,因为每次添加元素时都需要遍历整个新List来检查是否存在。

private static void m1() {
    List<Integer> initList = Arrays.asList(70, 70, -1, 5, 3, 3, 4, 4, 4, 4, 99);
    List<Integer> srcList = new ArrayList<>(initList);
    List<Integer> newList = new ArrayList<>();

    for (int i = 0; i < srcList.size(); i++) {
        if (!newList.contains(srcList.get(i))) {
            newList.add(srcList.get(i));
        }
    }
    System.out.println(newList);
}

运行结果如下:

image.png

2. 进阶方法:使用Set去重

Set是一种不允许重复元素的集合,因此可以利用这一特性来去除List中的重复元素。这里可以使用HashSet或者LinkedHashSet,前者不保证元素的顺序,而后者则保持元素的插入顺序。

private static void m2()
{
    List<Integer> srcList = Arrays.asList(70,70,-1,5,3,3,4,4,4,4,99);
    // 使用HashSet不保证顺序
    List<Integer> newList = new ArrayList<>(new HashSet<>(srcList));
    newList.forEach((s) -> System.out.print(s+" "));
    System.out.println();
    System.out.println();
    // 使用子类LinkedHashSet保证顺序
    newList = new ArrayList<>(new LinkedHashSet<>(srcList));
    newList.forEach((s) -> System.out.print(s+" "));
    System.out.println();
    System.out.println();
}

运行结果如下:

image.png

3. Stream流式计算

Java 8引入了Stream API,提供了一种更为简洁和高效的方式来处理集合。通过使用distinct()方法,可以轻松去除List中的重复元素,并且代码更加简洁易读,这个去重是十分方便的.

private static void m3() {
    List<Integer> initList = Arrays.asList(70, 70, -1, 5, 3, 3, 4, 4, 4, 4, 99);
    List<Integer> srcList = new ArrayList<>(initList);
    List<Integer> newList = srcList.stream().distinct().collect(Collectors.toList());
    newList.forEach((s) -> System.out.print(s + ", "));
}

运行结果如下: image.png

4. 使用indexOf和lastIndexOf前后索引不一致

这种方法通过比较元素的第一次出现和最后一次出现的索引来判断是否存在重复。如果两个索引不一致,则说明存在重复元素,可以将其从List中移除。


private static void m4()
{
    List<Integer> initList = Arrays.asList(70,70,-1,5,3,3,4,4,4,4,99);
    // 使用ArrayList进行remove操作
    List<Integer> srcList = new ArrayList<>(initList);
    List<Integer> newList = new ArrayList<>(initList);

    System.out.println(srcList.indexOf(70));
    System.out.println(srcList.lastIndexOf(70));


    for (Integer element : srcList) {
        // 前后索引不一致,说明有重复
        if(newList.indexOf(element) != newList.lastIndexOf(element)) {
            newList.remove(newList.lastIndexOf(element));
        }
    }
    newList.forEach((s) -> System.out.print(s+", "));
    System.out.println();
    System.out.println();
}

运行结果,可以看到列表中元素70的下标分别为0,1 image.png

5. 双for循环对比

这是一种较为传统的方法,通过嵌套for循环来比较元素是否相同,如果相同则从List中移除。这种方法的时间复杂度较高,不推荐在大数据量时使用。

private static void m5() {
    List<Integer> initList = Arrays.asList(70, 70, -1, 5, 3, 3, 4, 4, 4, 4, 99);
    List<Integer> srcList = new ArrayList<>(initList);
    List<Integer> newList = new ArrayList<>(initList);

    for (int i = 0; i < newList.size() - 1; i++) {
        for (int j = newList.size() - 1; j > i; j--) {
            if (newList.get(j).equals(newList.get(i))) {
                newList.remove(j);
            }
        }
    }
    newList.forEach((s) -> System.out.print(s + " "));
}

可以看到每一次都要遍历一次列表进行对比。

image.png

总结

以上五种方法各有优劣,适用于不同的场景。基础方法简单易懂,但效率较低;进阶方法和Stream流式计算更为高效且代码简洁;使用indexOf和lastIndexOf的方法较为直观;双for循环对比则应尽量避免在大数据量时使用,在实际开发中,应根据具体需求选择最合适的方法。个人觉得比较方便的是使用java8的stream进行过滤。