【问题标题】:Majority Element using divide-and-conquer algorithm使用分治算法的多数元素
【发布时间】:2016-08-16 02:09:04
【问题描述】:

大家! 长度为 n 的序列中的一个元素如果在序列中出现严格超过 n/2 次,则称为多数元素。

此代码问题的目标是检查输入序列是否包含多数元素。

我正在尝试使用归并排序算法来解决这个问题

我的策略:

  1. 排序序列,使用合并算法

  2. 在排序列表中查找每个元素的出现。如果大于 n/2,则返回 1。由于列表已排序,我想遍历列表,如果下一个元素与前一个不同,则计数器停止并将其与 n/2 进行比较

    def merge(left,rigt):
        result = []
        i = j = 0
        while i < len(left) and j < len(rigt):
            if left[i] <= rigt[j]:
                result.append(left[i])
                i += 1
    
            else:
                result.append(rigt[j])
                j += 1
    
        result += left[i:]
        result += rigt[j:]
    
        return result
    
    def merge_sort(a):
    if len(a) <= 1:
        return a
    
    middle = len(a)//2
    
    left = a[:middle]
    right = a[middle:]
    
    left = merge_sort(left)
    right = merge_sort(right)
    
    return list(merge(left,right))
    
    def get_major_element(a,n):
    
    k = 1
    
    for i in range(0,len(a)-1):
        if a[i] == a[i+1]:
            k += 1
    
    if k > n/2:
        return 1
    
    else:
        return 0
    
    if __name__ == '__main__':
        input = sys.stdin.read()
        data = list(map(int, input.split()))
        n = data[0]
        a = data[1:]
        m = merge_sort(a)
        print (get_major_element(m,n))
    

我得到的结果是无效的。 我想,我可以在没有初始排序的情况下做到这一点,但我不知道应该重写哪一步!有人可以帮忙吗?

【问题讨论】:

  • 您没有使用sortedlist.sort 的任何特殊原因?我想这是一个任务。如果作业是关于排序的,你应该在你的问题中说明(这样我们就不会提出不同的方法);如果它不是关于排序并且您只是使用排序来解决问题,则只需使用 bultin sort 函数。
  • 另外,您是否尝试过使用collections.Counter(the_list).most_common(1)
  • 有一个众所周知的标准算法可以在数组和 O(1) 空间上一次通过即可解决这个问题。 cs.utexas.edu/~moore/best-ideas/mjrty/example.html

标签: python algorithm sorting


【解决方案1】:

我会创建一组唯一元素并计算它们在原始列表中的出现次数,然后将最大值与列表长度进行比较:

def get_major_element(my_list):
    available_items = set(my_list)
    max_count, max_item = max((my_list.count(item), item) for item in available_items)
    return max_item if max_count > len(my_list)/2 else None

See this code running on ideone.com

【讨论】:

  • 那是我首先想到的,但将是有效的解决方案。我这里需要实现分治算法
  • 什么是分治算法?如果你能解释一下,这样我们就知道你想要什么了。
  • @ByteCommander 一种“分而治之”的算法是一种可以将问题递归地切割成更小的子问题的算法,直到为每个子子问题找到一个简单的案例,然后将它们组合起来全部回到一个全球解决方案。 Wikipedia
【解决方案2】:

将你的数组分成两半,左半边和右半边。请注意,如果一个元素是整个数组的大多数,那么它是至少一半的大多数。

所以要找到一个数组的大部分,递归地找到两半的大多数,然后在数组上单次计算两个候选者在整个数组中出现的次数,以检查它们中的哪一个是整个数组的大部分。

【讨论】:

    【解决方案3】:

    如果您有理由不使用其他人指出的内置排序和计数机制,这将一次性完成,而无需使用非常基本的数据类型。许多内置操作可能包含循环,在最坏的情况下可能使它们成为 O(n**2)。

    def getMajor(L):
        best = None
        elements = {}
        for element in L:
            elements[element] += 1
            if elements[element] > elements.get(best, 0):
                best = element
    
        if elements.get(best, 0) > len(L)/2:
            return best, elements.get(best, 0)
        else:
            return None, 0
    

    【讨论】:

      【解决方案4】:

      检查 moore 算法,它分两遍工作,并在 O(N) 中找到多数元素

      或者简单地对中间索引(startIndex + endIndex)/2 上的数组和元素进行排序,应该是多数元素。 (如果数组中有多数元素)。

      【讨论】:

        【解决方案5】:
        # Uses python3
        import sys
        
        def get_majority_element(a, left, right):
            if left == right:
                return -1
            if left + 1 == right:
                return a[left]
        
        
            left_elemt = get_majority_element(a,left,(left + right - 1) // 2 + 1)
            right_elemt = get_majority_element(a,(left + right - 1) // 2 + 1,right)
        
            l_count = 0
            for i in range(left,right):
                if a[i] == left_elemt:
                    l_count += 1
            if l_count > (right - left)//2:
                return left_elemt
        
            rcount = 0
            for i in range(left, right):
                if a[i] == right_elemt:
                    rcount += 1
            if rcount > (right - left) // 2:
                return right_elemt
        
            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)
        

        我花了很多时间在这个上。和你有同样的问题和困惑。看起来中间的函数应该是 (left + right - 1) // 2 + 1(归功于 mablatnik 的 git )(虽然我还没有弄清楚为什么)

        【讨论】:

          【解决方案6】:

          它在 java 中对我有用

          k=1;
          for(c=0;c<n-1;c++){
              if(array[c]==array[c+1])
                k+=1;
          
              else k=0;
          
          
              if (k > n/2){
                System.out.print("1");
                break;
          
              }
            }
            if (k <=n/2){
                System.out.print("0");
          }
          

          【讨论】:

          • 问题是关于Python的,你的代码假设数组是有序的,问题中没有说明。
          【解决方案7】:

          https://stackoverflow.com/a/56161162/13467399

          谢谢你的帖子,伙计。我正在为这个问题挠头。我看到你想知道为什么作者通过 (left + right - 1) // (2 + 1) 找到中点。

          这是因为这里的“正确”取的是数组的大小,而数组总是从 0 而不是 1 开始,这就是在除数中加 1 的答案。

          其实可以用(left + right) / 2计算中点。

          抱歉,我没有权限,无法在您的帖子中发表评论。

          【讨论】:

          • 这不是问题的答案,它应该是对您所指答案的评论。另外,请注意括号,因为在这种情况下,(2 + 1) 由于运算符优先级是不正确的,这在他们的回答中是正确的。
          • 对不起,我没有足够的特权点,我无法在他的帖子中发表评论。感谢您指出我在回答中的错误之处。
          猜你喜欢
          • 2018-10-16
          • 2020-05-31
          • 2015-09-05
          • 1970-01-01
          • 2021-12-27
          • 2011-08-21
          • 1970-01-01
          • 2012-10-28
          相关资源
          最近更新 更多