有没有人能够想出一种在线性时间内确定列表中多数元素的算法?该算法应使用 O(1)
空间。
如果 n 是列表的大小,则 多数元素 是至少出现 ceil(n/2)
次的元素。
[Input] 1, 2, 1, 1, 3, 2
[Output] 1
[编辑说明]这个问题存在技术错误。为了不破坏已接受答案的措辞,我选择保留它,并请查看已接受答案,该答案纠正了错误并解释了原因。
有没有人能够想出一种在线性时间内确定列表中多数元素的算法?该算法应使用 O(1)
空间。
如果 n 是列表的大小,则 多数元素 是至少出现 ceil(n/2)
次的元素。
[Input] 1, 2, 1, 1, 3, 2
[Output] 1
[编辑说明]这个问题存在技术错误。为了不破坏已接受答案的措辞,我选择保留它,并请查看已接受答案,该答案纠正了错误并解释了原因。
如果n是列表的大小,则多数元素是至少出现ceil(n/2)次的元素。
如果存在严格多数元素,则Boyer-Moore算法会找到一个具有严格多数的元素。 (如果您事先不知道是否确实有这样的元素,则必须对列表进行第二次遍历以检查结果。)
对于严格多数,您需要“......严格超过floor(n/2)次”,而不是“......至少出现ceil(n/2)次”。
在您的示例中,“1”出现3次,其他值也出现3次:
示例输入:1、2、1、1、3、2
输出:1
但是您需要具有相同值的4个元素才能获得严格多数。
它碰巧在这个特定情况下起作用:
输入:1、2、1、1、3、2 读取1:计数==0,因此将候选项设置为1,并将计数设置为1 读取2:计数!=0,元素!=候选人(1),因此将计数减少到0 读取1:计数==0,因此将候选项设置为1,并将计数设置为1 读取1:计数!=0,元素==候选人(1),因此将计数增加到2 读取3:计数!=0,元素!=候选人(1),因此将计数减少到1 读取2:计数!=0,元素!=候选人(1),因此将计数减少到0 结果是当前候选人:1
但是请看如果最后的“1”和末尾的“2”互换会发生什么:
输入:1, 2, 1, 2, 3, 1 读取1:count == 0,因此将候选项设置为1,并将计数设置为1 读取2:count != 0,element != candidate(1),因此将计数减少为0 读取1:count == 0,因此将候选项设置为1,并将计数设置为1 读取2:count != 0,element != candidate(1),因此将计数减少为0 读取3:count == 0,因此将候选项设置为3,并将计数设置为1 读取1:count != 0,element != candidate(3),因此将计数减少为0 结果是当前候选项:3
Boyer-moore算法:http://www.cs.utexas.edu/~moore/best-ideas/mjrty/index.html
你扫描一个列表(或流)并维护一个计数器。最初counter = 0
,majority_element = null
。当你扫描时,如果计数器为0,则将当前元素视为主要元素并增加计数器。如果counter != 0
,则根据当前元素是否为当前多数元素增加或减少计数器。
如果没有多数,这种算法无法给出多数。如果您想了解正确性级别,则还需要进行一次验证,以确保它实际上是多数(即,>= 50%)。
O(log n)
的空间,但由于n
被限制为2^32或2^64,并且您的计算机实际上是一个有着~8^(ramsize+hddsize)状态的有限状态机,所有操作都是O(1)
的。O(1)
空间中被识别。我将对“识别具有大多数元素的数组”和“查找大多数元素(如果存在)”的等价性进行一些手波。现在,泵引理是证明一个语言不是正则的标准工具,而且非常容易使用。通过它,您可以证明由具有大多数元素的数组组成的语言不是正则的。(作为练习,请尝试找到一个正则表达式,匹配具有大多数元素的这样的字符串,其中成员可以是ASCII字母。你做不到。) - R.. GitHub STOP HELPING ICEn
需要O(log n)或至少O(log log n)的空间。 - R.. GitHub STOP HELPING ICEO(1)
实际上是错误的。存储是一个或多个整数变量,其值可以达到 n
,因此需要 log n
的空间。然而,对于实际目的,log n
通常被限制在像 32 或 64 这样的常数范围内。 :-) - R.. GitHub STOP HELPING ICE如果你知道大多数元素在数组大小的一半以上,那么就有这样的算法。 您需要跟踪最常见的元素及其重复次数。当您开始时,该元素是第一个,并且有一个重复。如果下一个元素与当前最常见元素不同,则从重复中减去一。如果重复次数变为零,则将最常见元素更改为您当前正在观察的元素,并将重复次数设置为1。
使用堆排序的预阶段:
为数组元素构建一个堆,其运行时间为线性时间 -> O(n)。
然后取(N/2)个元素并搜索它的上层父节点是否全部相等 -> O(n/2)
如果全部相等,则(N/2)个元素是答案。
因此,总体时间复杂度为O(n) + O(n/2) -> O(n)。
我可能错了,但是在O(n)的执行时间和常量内存使用的组合似乎对我来说是不可能的。不使用额外的空间需要进行排序。最快的比较排序是O(n log n)。
使用基数排序,您可以获得更好的最坏情况执行时间,但会增加更多的内存使用。
O(1)
的空间解决方案。 - R.. GitHub STOP HELPING ICE