【问题标题】:What is the fastest algorithm to find an element with highest frequency in an array在数组中找到频率最高的元素的最快算法是什么
【发布时间】:2013-03-13 14:14:27
【问题描述】:

我有两个输入数组 X 和 Y。我想返回数组 X 中在数组 Y 中出现频率最高的那个元素。

这样做的简单方法要求对于数组 X 的每个元素 x,我线性搜索数组 Y 的出现次数,然后返回具有最高频率的元素 x。这是伪算法:

 max_frequency = 0
 max_x = -1             // -1 indicates no element found
 For each x in X
     frequency = 0
     For each y in Y
         if y == x
             frequency++
     End For
     If frequency > max_frequency
         max_frequency = frequency
         max_x = x
     End If
 End For
 return max_x

由于有两个嵌套循环,该算法的时间复杂度为 O(n^2)。我可以在 O(nlogn) 或更快的时间内做到这一点吗?

【问题讨论】:

  • 在讨论具有两个或多个维度的问题时,通常最好使用每个维度的变量来讨论复杂性。由于X < Y,我们可以取Y = N 并得到二次复杂度。实际上,O(X * Y) 可以更好地说明实际工作量。

标签: algorithm sorting search complexity-theory


【解决方案1】:

使用哈希表将键映射到计数。对于数组中的每个元素,请像 counts[element] = counts[element] + 1 或您的语言等效项一样。

最后,遍历哈希表中的映射并找到最大值。

【讨论】:

  • 为清楚起见,时间复杂度为O(X + Y),是这里给出的最好的。
【解决方案2】:

或者,如果您可以拥有其他数据结构,您可以遍历数组 Y,每个数字在哈希表中更新其频率。这需要O(N(Y) 时间。然后走 X 找出 X 中哪个元素的频率最高。这需要O(N(X)) 时间。总体而言:线性时间,并且由于您必须在任何实现中至少查看一次 XY 的每个元素(编辑:严格来说,这并非在所有情况下都正确/全部jwpat7 指出,尽管在最坏的情况下确实如此),但你不能比这更快。

【讨论】:

  • 在任何实现中,您必须至少查看 X 和 Y 的每个元素一次,这是不正确的。例如,假设我们计算 Y 中每个值的出现次数。如果 f 是 Y 中出现频率最高的元素,并且在扫描 X 时遇到 f,我们不需要查看 X 的其余部分。或者,如果 X 的某个元素 X0发生 k 次,只要 Y 的大小减去 X 到目前为止扫描的元素的频率之和低于 k,我们就不需要考虑 X 的任何其他元素。
  • @jwpat7:你是对的,我的立场是正确的。我在考虑一个平均/最坏的情况。既然你提出来了,还有其他边界情况,比如X包含一个元素,或者如果你先看X然后看Y你可以停止看Y[n+1]如果你已经知道Y[n]Y中出现频率最高的元素,也在X.
【解决方案3】:

常用算法的时间复杂度如下:

Algorithm     |   Best    |   Worst   |  Average
--------------+-----------+-----------+---------- 
MergeSort     | O(n lg n) | O(n lg n) | O(n lg n)  
InsertionSort |   O(n)    |  O(n^2)   |  O(n^2)  
QuickSort     | O(n lg n) |  O(n^2)   | O(n lg n)  
HeapSort      | O(n lg n) | O(n lg n) | O(n lg n)  
BinarySearch  |   O(1)    |  O(lg n)  |  O(lg n)  

一般来说,当遍历一个列表来满足某个条件时,你真的不能做得比线性时间更好。如果您需要对数组进行排序,我会说坚持使用 Mergesort(非常可靠)来查找数组中频率最高的元素。

注意:这是假设您要使用排序算法。否则,如果您被允许使用任何数据结构,我将使用具有恒定查找时间的 hashmap/hashtable 类型结构。这样,您只需匹配键并更新频率键值对。希望这可以帮助。

【讨论】:

  • 遍历列表通常在线性时间内完成。除非您确实需要排序,否则很多情况都可以在 O(N) 内处理。
  • @cHao 同意。取决于问题要求。
  • 二分查找对这张表有什么作用?
  • 我不想使用散列表或任何基于链表的结构。静态数组或动态数组是我比较喜欢使用的数据结构。
  • @nurabha 你最好的办法是使用排序算法,然后使用 nlogn 时间复杂度。
【解决方案4】:

第一步:对XY进行排序。假设它们对应的长度是 mn,这一步的复杂度将是O(n log n) + O(m log m)

第二步:统计 Y 中的每个 Xi 并跟踪迄今为止的最大计数。在排序后的 Y 中搜索 XiO(log n)。第二步总复杂度为:O(m log n)

总复杂度:O(n log n) + O(m log m) + O(m log n),或简化:O(max(n,m) log n)

【讨论】:

    【解决方案5】:

    基于分而治之概念的合并排序为您提供 O(nlogn) 复杂度

    【讨论】:

      【解决方案6】:

      如果两个列表的长度均为 n,您建议的方法将是 O(n^2)。更可能的是列表可以有不同的长度,因此时间复杂度可以表示为 O(mn)。

      您可以将问题分为两个阶段: 1. 按频率对 Y 中的唯一元素进行排序 2. 从这个列表中找到 X 中存在的第一项

      由于这听起来像是一个家庭作业问题,所以我会让您考虑一下您可以多快完成这些单独的步骤。这些成本的总和将为您提供算法的总体成本。有许多方法会比您目前拥有的两种列表长度的乘积更便宜。

      【讨论】:

        【解决方案7】:

        对 X 和 Y 进行排序。然后进行归并排序。每次遇到 X 中的相同元素时,计算 Y 的频率。

        所以复杂度,O(nlogn) + O(mlogm) + O(m+n) = O(klogk) 其中n,m = X, Y的长度; k = max(m,n)

        【讨论】:

          【解决方案8】:

          可以进行快速排序,然后用一个变量来遍历它,该变量计算一行中有多少个数字+该数字是什么。那应该给你nlogn

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2010-10-02
            • 2016-12-20
            • 2011-11-07
            • 2019-08-15
            • 2019-07-07
            • 1970-01-01
            • 1970-01-01
            • 2021-12-11
            相关资源
            最近更新 更多