-2

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

我有一个列表列表

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

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

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

4

3 回答 3

3

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

传统的方法是遍历每个列表一次并收集时间值HashMap<Integer, Integer>(其中键是数字,值是时间)。然后,您只需要从 map 中收集所有值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 个列表和 2000 个元素的两倍2000 x 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
于 2016-03-29T14:50:18.463 回答
0

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

于 2016-04-07T20:43:29.660 回答
0

维护一个额外的计数数组,用于存储完全遍历的元素的计数。然后,在更新元素计数的同时遍历列表,并在更新元素的计数等于 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)

打印(最终答案)

于 2016-05-16T17:15:08.390 回答