线性时间多数算法?

时间:2010-11-25 19:53:14

标签: algorithm language-agnostic complexity-theory

有人能想到用于确定元素列表中的多数元素的线性时间算法吗?该算法应使用O(1)空格。

如果n是列表的大小,则多数元素是至少ceil(n / 2)次出现的元素。

[Input] 1, 2, 1, 1, 3, 2

[Output] 1

[编者注] 此问题存在技术错误。我宁愿离开它,以免破坏接受的答案的措辞,纠正错误并讨论原因。请检查接受的答案。

7 个答案:

答案 0 :(得分:14)

我猜想Boyer-Moore算法(由nunes链接并在其他答案中由cldy描述)是问题的预期答案;但问题中“多数元素”的定义太弱,无法保证算法能够正常工作。

  

如果n是列表的大小。多数元素是至少出现ceil(n / 2)次的元素。

Boyer-Moore算法找到一个严格多数的元素,如果这样的元素存在。 (如果您事先不知道您确实有这样的元素,则必须再次通过列表来检查结果。)

对于绝对多数,你需要“......严格超过地板(n / 2)次”,而不是“......至少是ceil(n / 2)次”。

在您的示例中,“1”出现3次,其他值出现3次:

  

输入示例:1,2,1,1,3,2

     

输出:1

但是你需要4个具有相同值的元素才能获得严格的多数。

它确实适用于这种特殊情况:

Input: 1, 2, 1, 1, 3, 2
Read 1: count == 0, so set candidate to 1, and set count to 1
Read 2: count != 0, element != candidate (1), so decrement count to 0
Read 1: count == 0, so set candidate to 1, and set count to 1
Read 1: count != 0, element == candidate (1), so increment count to 2
Read 3: count != 0, element != candidate (1), so decrement count to 1
Read 2: count != 0, element != candidate (1), so decrement count to 0
Result is current candidate: 1

但是看看如果最后的“1”和最后的“2”被交换会发生什么:

Input: 1, 2, 1, 2, 3, 1
Read 1: count == 0, so set candidate to 1, and set count to 1
Read 2: count != 0, element != candidate (1), so decrement count to 0
Read 1: count == 0, so set candidate to 1, and set count to 1
Read 2: count != 0, element != candidate (1), so decrement count to 0
Read 3: count == 0, so set candidate to 3, and set count to 1
Read 1: count != 0, element != candidate (3), so decrement count to 0
Result is current candidate: 3

答案 1 :(得分:9)

Boyer-moore算法:http://www.cs.utexas.edu/~moore/best-ideas/mjrty/index.html

您扫描列表(或流)并维护一个计数器。最初为counter = 0majority_element = null。在扫描时,如果计数器为0,则假定当前元素为多数元素并增加计数器。如果counter != 0,则根据当前元素是否为当前多数元素来递增或递减计数器。

如果没有一个算法,这个算法不会给你多数。如果你想要正确程度,你必须多再通过一次验证它实际上是大多数(即> = 50%)。

答案 2 :(得分:7)

这是一个受欢迎的挑战问题,答案是这是不可能的。具有多数元素的字符串语言不规则(pumping lemma很容易证明这一点),因此无法在常量空间中识别它。

当然诀窍是你需要一个占用O(log n)空间的计数器变量,但是因为n被2 ^ 32或2 ^ 64限制而你的计算机实际上是一个有限状态机~8 ^(ramsize + hddsize)状态,一切都是O(1)

答案 3 :(得分:7)

我认为使用Boyer-Moore是可能的,虽然不是直接的。

正如Matthew所说,Boyer-Moore只保证找到多数元素,对多数的定义略有不同,称为严格多数。你的定义稍微弱一点,但不是很多。

  1. 执行Boyer-Moore:O(N)时间,O(1)空间
  2. 检查候选人是否满足条件:O(N)时间,O(1)空间
  3. 如果没有,执行Boyer-Moore,但忽略“失败”候选人的实例:O(N)时间,O(1)空间
  4. 检查(新)候选人是否符合条件:O(N)时间,O(1)空间
  5. 1.和2.步骤是直截了当的。 3.因为通过删除失败的候选者的实例,我们现在正在寻找严格的多数元素。 4.是可选的,只有在可能不存在多数元素时才使用。

答案 4 :(得分:2)

如果您知道多数元素的数量超过数组大小的一半,那么就有这样的算法。 您可以跟踪最常见的元素及其重复。当你开始时,元素是第一个,并且有一个重复。如果下一个元素与当前最常见的元素不同,则从重复中减去一个元素。如果重复变为零,那么您使用当前观察的元素更改最常见的并将重复设置为1.

答案 5 :(得分:0)

我可能错了,但O(n)执行时间和常量内存使用的组合对我来说似乎是不可能的。不使用额外空间需要排序。最快的比较排序是O(n log n)。

使用Radix排序,可以获得更好的最坏情况执行时间,但内存使用量更多。

答案 6 :(得分:0)

使用堆排序的前期阶段:

  1. 为数组元素构建堆 以线性时间运行 - >为O(n)。

  2. 然后取第(N / 2)个元素&搜索     到它的上层父节点(如果全部)     是否相等 - >为O(n / 2)

    如果全部相等,则第(N / 2)个元素为ans。

  3. 总体上O(n)+ O(n / 2) - >为O(n)