繁体   English   中英

从列表中完全删除出现 n 次以上的元素的优化方法

[英]An optimized way to completely remove elements from a list that occur more than n times

解决方案.java

public class Solution {
public static ArrayList<Integer> solution(int[] data, int n){
    ArrayList<Integer> list = new ArrayList<>();
    if(n == 0){
        list.add(0);
        return list;
    }
    for (int x : data) {
        int sameTaskCount = 0;
        for (int y : data) {
            if (y == x)
                sameTaskCount++;
        }
        if (sameTaskCount <= n)
            list.add(x);
    }
    return list;
}
public static void main (String[] args) {
    int[] list = {1, 2, 2, 3, 3, 3, 4, 5, 5};
    int n = 1;
    ArrayList<Integer> newList = solution(list, n);
    System.out.println(newList);
}}

解决方案.java(使用 HashMap) HASMAP 不保留顺序,因此被刮掉

public class Solution1 {
public static ArrayList<Integer> solution(int[] data, int n){
    HashMap<Integer, Integer> elementCountMap = new HashMap<>();
    for (int i : data) {
        if(elementCountMap.containsKey(i))
            elementCountMap.put(i, elementCountMap.get(i)+1);
        else
            elementCountMap.put(i, 1);
    }
    elementCountMap.entrySet().removeIf(entry ->(entry.getValue() > n));
    return new ArrayList<>(elementCountMap.keySet());
}
public static void main (String[] args) {
    int[] list = {1, 2, 2, 3, 3, 3, 4, 5, 5};
    int n = 1;
    ArrayList<Integer> newList = solution(list, n);
    System.out.println(newList);
}}

是否有另一种方法可以减少执行时间? 我在这里使用的示例输入只是为了测试目的,输入最多可以是 99 个整数,并且输入不会总是被排序。 这两个程序都在 IDE 中运行良好,但是当我提交代码时它们都失败了多个测试用例。
这是实际的问题陈述:

编写一个名为solution(data, n)的 function ,它接收一个少于 100 个整数和一个数字n的列表,并返回相同的列表,但所有出现超过n次的数字都被完全删除。 返回的列表应保持与原始列表相同的顺序。 例如,如果 data 是 [5, 10, 15, 10, 7] 并且 n 是 1,则 solution(data, n) 将返回列表 [5, 15, 7] 因为 10 出现两次,因此从完整列出。

约束:Java 8,执行时间有限,无通配符导入

正如已经说过的,最好为输入数组/列表计算频率 map 并过滤掉超过给定阈值的元素:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Collectors;
import java.util.stream.Stream;

public class Solution {

    // solution for array
    public static List<Integer> solution(int[] arr, int n) {
        if (n < 1) {
            return Collections.emptyList();
        }
        Supplier<Stream<Integer>> streamSupplier = () -> Arrays.stream(arr).boxed();
        Map<Integer, Integer> freqMap = streamSupplier.get()
                            .collect(Collectors.groupingBy(x -> x, Collectors.summingInt(x -> 1)));
    
        return streamSupplier.get().filter(x -> freqMap.get(x) <= n).collect(Collectors.toList());
    }

    // solution for ArrayList
    public static List<Integer> solution(ArrayList<Integer> list, int n) {
        if (n < 1) {
            return Collections.emptyList();
        }
        Map<Integer, Integer> freqMap = list.stream()
                .collect(Collectors.groupingBy(x -> x, Collectors.summingInt(x -> 1)));

        list.removeIf(x -> freqMap.get(x) > n);

        return list;
    }

}

这个想法是创建数组中数字的频率 map ,然后过滤频率小于n的数字。 Stream API 以简洁明了的方式更容易完成。

import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
import java.util.stream.Collectors;

public class Main {
    public static List<Integer> solution(int[] data, int n) {
        return Arrays.stream(data)
                    .boxed()
                    .collect(Collectors.groupingBy(Function.identity())).values()
                        .parallelStream()
                        .filter(list -> list.size() <= n)
                        .flatMap(List::stream)
                        .collect(Collectors.toList());
    }

    public static void main(String[] args) {
        int[] list = { 1, 2, 2, 3, 3, 3, 4, 5, 5 };
        // Test
        int n = 2;
        System.out.println(solution(list, n));
    }
}

Output:

[1, 2, 2, 4, 5, 5]

Oracle关于Stream API的教程:

  1. 使用 Java SE 8 Streams 处理数据,第 1 部分
  2. 第 2 部分:使用 Java SE 8 流处理数据

与我之前的尝试相比,这似乎相对较快。 它是使分组过程短路的混合解决方案。 它使用 map 但仅供内部使用,因此它保留剩余元素的顺序并使用 Java 1.8 或更早版本。

  • 它只是使用列表值作为键将值组合在列表中。 所以每个列表都包含该大小的所有值(即重复)。
  • 一旦当前值的列表大小超过阈值,map 中针对该值的元素将从主列表中删除。
  • 该集合用于取消对已删除值的进一步处理。
  • 在所有元素的迭代之后,返回剩余的值列表。
public static List<Integer> solution(int[] data, int n) {
    Map<Integer, List<Integer>> map = new HashMap<>();
    List<Integer> list = new LinkedList<>();
    Set<Integer> set = new HashSet<>();
    for (int i : data) {
        if (set.contains(i)) {
            continue; // already removed
        }
        list.add(i);
        map.computeIfAbsent(i, k->new ArrayList<>()).add(i);
        List<Integer> temp = map.get(i);
        if (temp.size() > n) {
            set.add(i);
            list.removeAll(temp);
        }
    }
    return list;
    
}
public static void main(String[] args) {
    Random r = new Random(23);
    int[] data = r.ints(20, 1, 6).toArray();
    System.out.println(Arrays.toString(data));
    int n = 4;
    List<Integer> newList = solution(data,n);
    System.out.println(newList);
    
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM