有人能想到用于确定元素列表中的多数元素的线性时间算法吗?该算法应使用O(1)
空格。
如果n是列表的大小,则多数元素是至少ceil(n / 2)
次出现的元素。
[Input] 1, 2, 1, 1, 3, 2
[Output] 1
[编者注] 此问题存在技术错误。我宁愿离开它,以免破坏接受的答案的措辞,纠正错误并讨论原因。请检查接受的答案。
答案 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 = 0
,majority_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.和2.步骤是直截了当的。 3.因为通过删除失败的候选者的实例,我们现在正在寻找严格的多数元素。 4.是可选的,只有在可能不存在多数元素时才使用。
答案 4 :(得分:2)
如果您知道多数元素的数量超过数组大小的一半,那么就有这样的算法。 您可以跟踪最常见的元素及其重复。当你开始时,元素是第一个,并且有一个重复。如果下一个元素与当前最常见的元素不同,则从重复中减去一个元素。如果重复变为零,那么您使用当前观察的元素更改最常见的并将重复设置为1.
答案 5 :(得分:0)
我可能错了,但O(n)执行时间和常量内存使用的组合对我来说似乎是不可能的。不使用额外空间需要排序。最快的比较排序是O(n log n)。
使用Radix排序,可以获得更好的最坏情况执行时间,但内存使用量更多。
答案 6 :(得分:0)
使用堆排序的前期阶段:
为数组元素构建堆 以线性时间运行 - >为O(n)。
然后取第(N / 2)个元素&搜索 到它的上层父节点(如果全部) 是否相等 - >为O(n / 2)
如果全部相等,则第(N / 2)个元素为ans。
总体上O(n)+ O(n / 2) - >为O(n)