【问题标题】:Majority Element Python多数元素 Python
【发布时间】:2016-08-22 17:00:27
【问题描述】:

我在 Python 3 中的“多数元素”分而治之算法实现中无法获得正确的输出。

这应该是比较正确的;但是,我仍然会觉得我遗漏了一些东西,或者它有点不对劲,我不知道为什么会这样。

我尝试了一些调试语句和不同的东西。看起来在代码上方注释中列出的特定情况下,当它进行递归调用时,它为“left_m”解析-1,为“right_m”解析941795895。当它将每个索引处的元素与这些变量进行比较时,计数器显然永远不会增加。

我是不是走错了路?任何帮助将不胜感激。

谢谢。

# Input:
# 10
# 2 124554847 2 941795895 2 2 2 2 792755190 756617003
# Your output:
# 0
# 
# Correct output:
# 1

def get_majority_element(a, left, right):
 if left == right:
     return -1
 if left + 1 == right:
     return a[left]

 left_m = get_majority_element(a, left, (left + right - 1)//2)
 right_m = get_majority_element(a, (left + right - 1)//2 + 1, right)

 left_count = 0
 for i in range(0, right):
     if a[i] == left_m:
         left_count += 1
 if left_count > len(a)//2:
     return left_m

 right_count = 0
 for i in range(0, right):
     if a[i] == right_m:
         right_count += 1
 if right_count > len(a)//2:
     return right_m

 return -1

if __name__ == '__main__':
    input = sys.stdin.read()
    n, *a = list(map(int, input.split()))
    if get_majority_element(a, 0, n) != -1:
        print(1)
    else:
        print(0)

【问题讨论】:

  • 为什么给定样本输入的正确输出是1 而不是21 甚至不在输入中!
  • 我猜它应该是二进制的,比如如果有多数元素返回 1,否则返回 0。

标签: python algorithm python-3.x divide-and-conquer


【解决方案1】:

当计算左右主要元素的出现时,您的循环会超出范围(0,右)。相反,它们应该超出范围(左,右)。从 0 开始可能会导致在较小的子问题中返回不正确的主要元素。

另外,除了在你的 for 循环覆盖的范围内有不正确的起始索引的问题之外,你的递归调用参数似乎也有问题,这可能是由于你的直觉导致你忽略了一些细节。在整个 get_majority_element 函数中,您将参数 right 视为不在列表中的第一个索引,而不是将 right 视为列表中最右边元素的索引。

但是,在您的第一次递归调用中,您将第三个参数视为该列表中包含 的最后一个元素。如果 right 是不在该列表中的第一个元素的索引,它实际上应该与您在下一行中进行的第二个递归调用的第二个参数相同。因此,您进行的第一个递归调用的第三个参数比应有的值小 1,导致您每次递归下降时都会忽略 1 个元素

第三,你在 for 循环后面的 if 语句中有一个错误,类似于循环范围的问题。您正在为所有 len(a) 元素划分元素的出现,尽管您应该只关心您当前正在处理的子问题。因此,您应该将其除以该子问题中的元素数,而不是 len(a)。 (即(右-左)//2)

您可以在下面找到工作代码,并查看here 以观察其执行情况。

def get_majority_element(a, left, right):
    if left == right:
        return -1
    if left + 1 == right:
        return a[left]

    left_m = get_majority_element(a, left, (left + right - 1)//2 + 1)
    right_m = get_majority_element(a, (left + right - 1)//2 + 1, right)
    left_count = 0
    for i in range(left, right):
        if a[i] == left_m:
            left_count += 1
    if left_count > (right-left)//2:
        return left_m

    right_count = 0
    for i in range(left, right):
        if a[i] == right_m:
            right_count += 1
    if right_count > (right-left)//2:
        return right_m

    return -1

if __name__ == '__main__':
    input = sys.stdin.read()
    n, *a = list(map(int, input.split()))
    print("n=" + str(n))
    if get_majority_element(a, 0, len(a)) != -1:
        print(1)
    else:
        print(0)

【讨论】:

  • 我认为你对循环的看法是绝对正确的,我已经纠正了它们;但是,在我最初的示例中,我似乎遗漏了一个关键的 return 语句,该语句在所有其他条件都不满足时返回 -1。我现在已经添加了这个。先前状态下的示例总是返回-1 以外的值。当我添加这个return语句时,输出仍然不正确,所以也许可以调整它的位置?
  • @chrisl0lz 我更新了我的答案以包括你的情况。
  • 啊,我明白了,我想我可能一直对什么构成子问题的 1...N 个元素感到困惑。我假设当切片数组再次应用于函数时,len(a)//2 将是适当的 N 个元素;但是,正如您指出的那样,情况并非如此,我需要一个更合适的长度来解决子问题。感谢您对此的帮助。
【解决方案2】:

我正在尝试使用 Boyers 和 Moore 的算法来查找列表中的多数元素。我正在使用内置函数 count;因此,如果多数元素大于列表的一半大小,则输出为 1,否则为 0。您可以在此链接中找到更多关于 Boyers and Moore's Algorithm on Finding Majority Algorithm information here

# Uses python3
import sys

def get_majority_element(a,n):
    maximum = a[0]
    amount = 1
    for i in (a[1:]):
        if not  maximum == i:
            if amount >= 1:
                amount = amount - 1
            else:
                maximum = i
                amount = 1
        else:
            amount = amount + 1
    output = a.count(maximum)
    if output > n//2:
        return 1
    return 0



if __name__ == '__main__':
    input = sys.stdin.read()
    n, *a = list(map(int, input.split()))
    print (get_majority_element(a,n))

【讨论】:

    猜你喜欢
    • 2019-05-09
    • 1970-01-01
    • 1970-01-01
    • 2016-06-03
    • 1970-01-01
    • 2012-01-18
    • 1970-01-01
    • 2021-10-14
    • 1970-01-01
    相关资源
    最近更新 更多