【发布时间】:2014-09-01 16:25:53
【问题描述】:
这个问题是 Skiena 的 4-11。找到多数元素的解决方案 - 重复超过一半是多数算法。我们可以用它找出所有重复 n/4 次的数字吗?
【问题讨论】:
-
这个练习可能要求使用 n/2 的方法的思想,而不是将算法作为子程序。
这个问题是 Skiena 的 4-11。找到多数元素的解决方案 - 重复超过一半是多数算法。我们可以用它找出所有重复 n/4 次的数字吗?
【问题讨论】:
由于您没有提到空间复杂度,一种可能的解决方案是使用 hashtable 映射到计数的元素,然后如果找到该元素,您可以增加计数。
【讨论】:
请参阅this paper,了解使用常量内存并以线性时间运行的解决方案,该解决方案将为出现超过 n/4 次的元素找到 3 个候选者。请注意,如果您假设您的数据是作为只能通过一次的流给出的,那么这是您能做的最好的 - 您必须再通过一次流来测试 3 个候选人中的每一个,看看是否它在流中出现超过 n/4 次。但是,如果您先验地假设有 3 个元素出现超过 n/4 次,那么您只需要通过流一次,这样您就可以得到一个线性时间在线算法(只通过流一次),它只需要常数存储。
【讨论】:
通过摩尔投票算法找到出现n/2 times的多数元素
请参阅摩尔投票算法 (http://www.geeksforgeeks.org/majority-element/) 给定链接的方法 3。
时间:O(n)
现在找到多数元素后,再次扫描数组并remove the majority element 或使其成为-1.
时间:O(n)
现在对数组的剩余元素应用摩尔投票算法(但现在忽略 -1,因为它之前已经包含在内)。新的多数元素出现n/4 times.
时间:O(n)
总时间:O(n)
额外空间:O(1)
您可以对出现超过 n/8,n/16,.... 次的元素执行此操作
编辑:
可能存在数组中没有多数元素的情况:
例如如果输入数组是{3, 1, 2, 2, 1, 2, 3, 3},那么输出应该是[2, 3]。
给定一个大小为 n 的数组和一个数字 k,找出所有出现次数超过 n/k 次的元素
请参阅此链接以获取答案: https://stackoverflow.com/a/24642388/3714537
参考资料:
【讨论】:
Misra and Gries 描述了几种方法。我不完全理解他们的论文,但一个关键的想法是使用袋子。
Boyer and Moore's original majority algorithm paper 有很多关于 FORTRAN 代码形式验证的难以理解的证明和讨论,但它对多数算法的工作原理有一个很好的解释开始。关键概念始于这样一个想法,即如果大多数元素是 A 并且您一次删除一个 A 的副本和其他内容的副本,那么最终您将只有A。接下来,应该清楚的是,删除两个不同的项目,两者都不是A,只能增加A 持有的多数。因此,删除 任何 对项目是安全的,只要它们不同。然后可以将这个想法具体化。从列表中取出第一项并将其粘贴在一个盒子中。取出下一个物品并将其粘在盒子里。如果他们是一样的,让他们都坐在那里。如果新的不同,请将其与盒子中的物品一起扔掉。重复直到所有物品都在盒子里或垃圾桶里。由于盒子一次只允许有一种物品,因此可以非常有效地表示为一对(item type, count)。
找到所有可能出现超过n/k 次的项目的概括很简单,但解释它的工作原理有点困难。基本思想是我们可以找到并销毁k distinct 元素组,而无需更改任何内容。为什么?如果w > n/k 则w-1 > (n-k)/k。也就是说,如果我们去掉一个流行元素,同时也去掉k-1other元素,那么流行元素仍然流行!
实现:不只允许 一个 类型的项目在框中,而是允许 k-1 个项目。每当您看到一组 k 不同 项目出现时(也就是说,框中有 k-1 类型,而到达的类型与它们中的任何一个都不匹配),你扔一个垃圾箱中的每种类型,包括刚刚到达的那种。我们应该为这个“盒子”使用什么数据结构?好吧,当然是一个包!正如 Misra 和 Gries 所解释的,如果可以对元素进行排序,那么具有 O(log k) 基本操作的基于树的包将使整个算法的复杂度为 O(n log k)。需要注意的一点是,删除每个元素之一的操作很昂贵(我认为 O(k log k)),但该成本在这些元素的到达时分摊,所以没什么大不了的。当然,如果您的元素是可散列的而不是可排序的,则可以改用基于散列的包,在某些常见假设下,它会提供更好的渐近性能(但不能保证)。如果您的元素是从一个小的有限集合中提取的,您可以保证这一点。如果它们只能比较平等,那么你的包会变得更贵,我很确定你最终会得到像 O(nk) 这样的东西。
【讨论】: