给出的问题:
多集合是一个集合,其中一些元素出现超过一次(例如{a,f,b,b,e,c,b,g,a,i,b}是多集)。元素是从完全有序的集合中提取的。当呈现多集作为输入时,呈现算法,找到多集中出现次数最多的元素(例如,在{a,f,b,b,e,c,b,g,a,c,b}中, b出现次数最多)。算法 应该在O(n lg n / M + n)时间运行,其中n是多集合中元素的数量,M是多集合中元素出现的最高数量。请注意,您不知道M的值。
[提示:根据列表的中位数使用分而治之的策略。由分而治之策略产生的子问题不能按顺序小于“某个”大小 达到给定的时间限制。]
我们最初的解决方案:
我们的想法是使用摩尔的多数算法来确定多重集合是否包含多数候选(例如{a,b,b}占多数,b)。在确定这是真还是假之后,我们要么输出结果,要么使用给定算法(称为Select)找到列表的中位数,并将列表拆分为三个子列表(小于等于中位数的元素,以及大于中位数)。同样,我们会检查每个列表以确定是否存在多数元素,如果存在,那就是结果。
例如,给定多重集{a,b,c,d,d,e,f}
第1步:检查多数。找不到,根据中位数拆分列表。
步骤2:L1 = {a,b,c,d,d},L2 = {e,f}找到每个的大部分。找不到,再次拆分列表。
步骤3:L11 = {a,b,c} L12 = {d,d} L21 = {e} L22 = {f}检查每个元素的多数元素。 L12返回d。在这种情况下,d是原始multiset中最常出现的元素,因此就是答案。
我们遇到的问题是这种类型的算法是否足够快,以及这是否可以递归完成,或者是否需要终止循环。就像提示所说的那样,子问题不能小于'某个'大小,我们认为这个大小是M(出现次数最多)。
答案 0 :(得分:1)
如果你想在现实生活中这样做,值得考虑使用哈希表来跟踪计数。这可以为每个哈希表访问分配O(1)复杂度,因此以下Python代码的总体复杂度为O(n)。
import collections
C = collections.Counter(['a','f','b','b','e','c','b','g','a','i','b'])
most_common_element, highest_count = C.most_common(1)[0]
答案 1 :(得分:1)
如果您按照帖子中的描述以最直接的方式使用递归,则它将没有所需的时间复杂度。为什么?让我们假设答案元素是最大的一个。然后它总是位于递归的右分支中。但是我们首先调用左分支,如果所有元素在那里都是不同的,则可以更深入(获得大小为1
的部分,而我们不希望它们小于M
)。
这是一个正确的解决方案:
让我们总是将每个步骤将数组拆分为三个部分,如问题中所述。现在让我们一步一步看看我们拥有的东西:递归调用形成一棵树。为了获得所需的时间复杂度,我们永远不应该比答案所在的级别更深入。为了实现这一点,我们可以使用带队列的广度优先搜索而不是深度优先搜索来遍历树。而已。