查找列表中出现次数超过 k 次的所有元素的最佳方法

Best way to find all elements in a list that are present more than k times

我刚遇到一个问题,我想知道解决这个问题的最佳方法是什么。

我有一个列表列表

L = [[1, 2, 3, 4, 5, 6, 7], [2, 4, 6, 8, 10, 12], [3, 6, 9, 12, 15], ....]

假设 L 的大小是 n,找到所有存在的元素的最佳方法是什么 k 次或更多次 L?

例如,如果k = 2,那么我应该得到 [2, 3, 4, 6, 12].

Assuming the size of L is n, what would be the best way to find all the elements that are present k or more times in L?

传统方法是遍历每个列表一次并在HashMap<Integer, Integer>中收集时间值(其中键是数字,值是时间)。然后你只需要从地图中收集所有值为 k 或更多的键:

 public static List<Integer> getResultListByMap(List<List<Integer>> inputList, int k) {
    Map<Integer, Integer> times = new HashMap<>();
    for (List<Integer> integers : inputList) {
        for (Integer integer : integers) {
            if (times.keySet().contains(integer)) {
                times.put(integer, times.get(integer) + 1);
            } else {
                times.put(integer, 1);
            }
        }
    }

    List<Integer> result = new ArrayList<>();
    for (Map.Entry<Integer, Integer> entry : times.entrySet()) {
        if (entry.getValue() >= k) {
            result.add(entry.getKey());
        }
    }
    return result;
}

result 列表包含列表中出现 k 次或更多次

的所有数字

更新: 好的,我知道您已经使用了 HashMap 方法,但它对您来说很慢。我编写了一个具有 Java 8 Stream API 功能的算法,该算法使用列表连接、排序并从并行性中获得好处:

public static List<Integer> getResultListBySort(List<List<Integer>> inputList, int k) {
    List<Integer> newList = inputList.parallelStream()
            .flatMap(l -> l.parallelStream()).sorted().collect(Collectors.toList());

    List<Integer> result = new ArrayList<>();

    Integer prev = null;
    int sum = newList.get(0);
    for (Integer integer : newList) {
        if (integer.equals(prev)) {
            sum++;
        } else {
            if (sum >= k) {
                result.add(integer);
            }
            sum = 1;
        }
        prev = integer;
    }
    return result;
}

对于 2000 x 2000 问题大小 - 2000 个包含 2000 个元素的列表(现在只需半秒即可在我的 PC 上获取结果列表)

Benchmark                       Mode  Samples  Score  Score error  Units
c.c.b.MyBenchmark.testMap       avgt       20  0,972        0,030   s/op
c.c.b.MyBenchmark.testSorted    avgt       20  0,534        0,005   s/op

这完全取决于对 L 执行操作的频率。考虑到您偶尔会执行此操作,那么用 O(n_1+n_2+[ 就可以找到结果=14=]+...+n_n) 时间复杂度。即,每次通过遍历数组数组和计数来找出答案。如果这是一个频繁的操作,为什么不对数组的数组进行排序或者为什么不使用缓存。我相信最好的方法完全取决于你的使用方式。

维护一个额外的计数数组,用于存储完全遍历的元素的计数。然后,在更新元素计数的同时遍历列表,在更新元素计数是否等于 k ​​的同时,将其添加到最初为空的最终答案列表。但是要使其正常工作,您应该知道给定数组中的最大元素。

final_answer = []
count = [0 for i in range(max_el)] # put very large number here e.g. 1000
for sublist in L:
    for element in sublist:
        count[element] += 1
        if count[element] == k:
            final_list.append(element)

打印(final_answer)