【问题标题】:Best way to find all elements in a list that are present more than k times查找列表中存在超过 k 次的所有元素的最佳方法
【发布时间】:2016-03-29 14:42:35
【问题描述】:

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

我有一个列表列表

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].

【问题讨论】:

  • 你的意思是数组数组吗?
  • @Gendarme 在这种情况下重要吗?只是ints 的一些类似列表的容器。
  • 将列表/数组展平,得到频率。
  • 是的。数组数组、ArrayList 的 ArrayList(如果您使用 Java)或类似的东西。
  • @thisisshantzz 我们可以帮助您的代码在哪里?

标签: java array-algorithms


【解决方案1】:

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

传统方式是遍历每个列表一次,并在HashMap<Integer, Integer> 中收集次数值(其中key 是数字,value 是次数)。然后你只需要从 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 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

【讨论】:

  • times.put(integer, 0); 不正确,是吗?当您第一次遇到该数字时,您不会将值1 放入地图中吗?
  • 我不是在谈论自动装箱,我在谈论应该是 1 而不是 0 的值。
  • 我正在做同样的事情,但我想知道是否有办法做到这一点而不必运行那个嵌套循环。在我的具体情况下,n = 3 并且各个列表本身可以有大约 2000 个元素。所以有点慢。
  • 如果不是列表列表,那么有没有更好的方法来做到这一点?我拥有的是 n 个条件和满足每个条件的值列表。我要查找的是有多少个值满足k个或更多条件。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

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

    打印(最终答案)

    【讨论】:

      猜你喜欢
      • 2021-08-29
      • 1970-01-01
      • 1970-01-01
      • 2019-07-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-10-14
      • 2012-04-20
      相关资源
      最近更新 更多