【问题标题】:Divide and Conquer. Find the majority of element in array分而治之。查找数组中的大多数元素
【发布时间】:2020-01-07 09:41:33
【问题描述】:

我正在研究一种 Python 算法来查找列表中出现频率最高的元素。

def GetFrequency(a, element):
return sum([1 for x in a if x == element])

def GetMajorityElement(a):
  n = len(a)
  if n == 1:
    return a[0]
  k = n // 2

  elemlsub = GetMajorityElement(a[:k])
  elemrsub = GetMajorityElement(a[k:])
  if elemlsub == elemrsub:
    return elemlsub

  lcount = GetFrequency(a, elemlsub)
  rcount = GetFrequency(a, elemrsub)

  if lcount > k:
    return elemlsub
  elif rcount > k:
    return elemrsub
  else:
    return None

我尝试了一些测试用例。有的通过了,有的没通过。

例如,[1,2,1,3,4] 这应该返回 1,但我得到 None。

实现遵循这里的伪代码: http://users.eecs.northwestern.edu/~dda902/336/hw4-sol.pdf 伪代码找到多数项并且需要至少一半。我只想找到大多数项目。

我能得到一些帮助吗? 谢谢!

【问题讨论】:

  • 您是希望仅在计数大于一半时才返回结果,还是只返回频率最高的元素?
  • @chen 该算法用于查找项目列表中的多数(如果有的话),其中多数意味着出现超过 50% 的时间。所以它不是为了找到最常见的项目。在您的示例中,有五个项目 [1,2,1,3,4] 但没有项目出现超过 50%,在这种情况下是三倍,因此没有多数。
  • @chen 这不是你的问题所说的,也不是你实现的算法应该做的。不,这不能用分而治之的方法来解决,因为你总是需要每个值的确切计数才能最终决定哪个值最频繁。
  • @chen 您的最后一次编辑完全改变了问题 - 仍然不清楚:您所说的“多数元素”是“最常见的元素”,而“多数元素”的意思是“最常见的元素”一个出现超过 n/2 次(如果存在)。请不要这样做,因为这会使所有 cmets、答案和作者的努力毫无意义。

标签: python algorithm


【解决方案1】:

我写了一个迭代版本,而不是你正在使用的递归版本,以防你想要类似的东西。

def GetFrequency(array):
    majority = int(len(array)/2)
    result_dict = {}
    while array:
        array_item = array.pop()
        if result_dict.get(array_item):
            result_dict[array_item] += 1
        else:
            result_dict[array_item] = 1
        if result_dict[array_item] > majority:
            return array_item   
    return max(result_dict, key=result_dict.get)

这将遍历数组并在一个超过总数的 50% 时返回值(作为多数)。否则遍历整个数组并返回频率最高的值。

【讨论】:

    【解决方案2】:
    def majority_element(a):
        return max([(a.count(elem), elem) for elem in set(a)])[1]
    

    编辑

    如果有平局,则返回最大值。例如:a = [1,1,2,2] 返回 2。可能不是您想要的,但可以更改。

    编辑 2

    你给出的伪代码分为数组 1 到 k包含,k + 1 到 n。您的代码执行 1 到 k - 1,k 到结束,但不确定它是否有很大变化?如果你想尊重你给出的算法,你应该这样做:

    elemlsub = GetMajorityElement(a[:k+1])  # this slice is indices 0 to k
    elemrsub = GetMajorityElement(a[k+1:])  # this one is k + 1 to n.
    

    同样根据您提供的伪代码,lcountrcount 应该与 k + 1 进行比较,而不是 k

    if lcount > k + 1:
      return elemlsub
    elif rcount > k + 1:
      return elemrsub
    else:
      return None
    

    编辑 3

    cmets highligted 中的一些人指出,提供的伪代码解决的不是最频繁的问题,而是出现次数超过 50% 的项目。因此,您的示例输出确实是正确的。您的代码很有可能已经按原样运行。

    编辑 4

    如果你想在出现平局时返回None,我建议这样做:

    def majority_element(a):
        n = len(a)
        if n == 1:
            return a[0]
    
        if n == 0:
            return None
    
        sorted_counts = sorted([(a.count(elem), elem) for elem in set(a)], key=lambda x: x[0])
    
        if len(sorted_counts) > 1 and sorted_counts[-1][0] == sorted_counts[-2][0]:
            return None
    
        return sorted_counts[-1][1]
    

    【讨论】:

    • 谢谢。但是,我想要一个分而治之的解决方案。是否可以修复我的算法中的错误?
    • 谢谢。代码是正确的。但是,我只希望算法找到最频繁的项目,它不需要至少 50% 的出现。 @Valentin B.
    • @chen 那么你提供的方法是无法实现的,我建议你使用我的任何一种方法,它们可能不是超级优化但它们应该可以正常工作。
    猜你喜欢
    • 2018-08-05
    • 2018-10-16
    • 2020-05-31
    • 2019-11-05
    • 2017-06-16
    • 2018-07-12
    • 2013-01-16
    • 2014-03-24
    相关资源
    最近更新 更多