假设给定一个n元素多重集A(未排序),我们 想要一个O(n)时间算法来确定A是否包含多数元素,即 在A中出现超过n / 2次的元素。在O(n)时间内很容易解决这个问题 使用线性时间选择算法,通过找到中位数(称之为x),然后计数 如果计数超过n / 2,则在A中出现x次并将其作为多数返回 (否则答案是“没有多数”)。现在考虑以下概括 问题:给定A和整数k < n,我们想要一个确定的算法 A是否包含一个超过n / k次的值(如果有很多这样的值 存在,然后它就足以找到其中一个)。设计一个算法来做到这一点,和 将其复杂性分析为n和k的函数。你在这个问题上的成绩将取决于 你的算法有多快(当然它也必须是正确的)。对于O(kn)时间算法给出10分的部分信用,对于O(n log k)时间算法给出完全信用。
现在我已经为这个问题提出了两个解决方案,但都没有完全满足 O(n log k)要求。我立刻看到我可以使用O(n log n)算法对数组进行排序然后查看是否有任何元素线性重复超过n / k次但是O(n log n)不是O(n log k)
我也发现并且稍微理解了通过使用与输入相同的数据类型的数组和k为long的int来完成O(nk)方法。然后将每个元素放入一个空元素中递增其计数器,或者如果它匹配一个元素递增其计数器直到我们到达第k + 1个唯一元素,此时你将所有计数器递减1直到一个达到0,此时它是被认为是空的,新元素可以放在其中。依此类推,直到输入数组结束。然后检查完成后剩下的所有元素,看它们是否出现超过n / k次。但由于这涉及检查n个原始元素对所有k个新数组元素,因此它是O(nk)。关于如何在O(n log k)中解决这个问题的任何提示?我认为O(nk)算法与他希望我们如何思考有关,但我不确定从何处开始。
答案 0 :(得分:7)
您描述的方法只需递归使用。
记住select
移动小于或等于中位数左侧中间值的元素。
如果A
的大小为n
。
找出A
的中位数。
现在找到由中位数划分的两个长度为n/2
的子多集中的每一个的中位数。
找出由中位数划分的四个长度为n/4
的子多集中的每一个的中位数。
递归继续,直到叶子长度为n/k
。
现在递归树的高度为O(lgk)
。
在递归树的每个级别上,都有O(n)
个操作。
如果存在重复至少n/k
次的值,那么它将在其中一个中
这些k
长度为n/k
个子多集。
最后的操作也在O(n)
中完成。
因此,您获得O(nlgk)
的请求运行时间。
答案 1 :(得分:2)
我想知道O(kn)算法是否可能更符合以下几点:
这个想法是,如果一个元素出现n / k次,它必须是其中之一。
也许你可以使用你的问题中提出的方案和树结构来保存k个元素。这就意味着搜索匹配只是log(k)而不是k,对于整体O(nlogk)?
请注意,您应该将树用于第一遍(您要找到我们需要考虑的候选人),以及计算每个元素的确切计数的第二轮。
另请注意,您可能希望使用延迟评估方案来递减计数器(即标记需要递减的整个子树,并仅在下次使用该路径时传播递减)。
如果你在现实生活中遇到这种情况,我会考虑使用基于哈希的字典存储直方图,因为这应该提供快速解决方案。
e.g。在Python中你可以使用
在(平均)O(n)时间内解决这个问题from collections import Counter
A=[4,2,7,4,6]
k=3
element,count = Counter(A).most_common()[0]
if count>=len(A)//k:
print element
else:
print "there is no majority"
答案 2 :(得分:0)
我不知道你是否看过这个,但它可能有助于你提出想法:
假设您知道数组L中有多数元素。
查找元素的一种方法如下:
Def FindMajorityElement(L):
Count = 0
Foreach X in L
If Count == 0
Y = X
If X == Y
Count = Count + 1
Else
Count = Count - 1
Return Y
O(n)时间,O(1)空间