找到数组中的多数元素

Ali*_*ini 51 arrays algorithm time-complexity

多数元素是发生超过数组大小一半的元素.

如何在数组中找到多数元素O(n)

输入示例:

{2,1,2,3,4,2,1,2,2}
Run Code Online (Sandbox Code Playgroud)

预期产量:

2
Run Code Online (Sandbox Code Playgroud)

小智 109

// returns -1 if there is no element that is the majority element, otherwise that element

// funda :: if there is a majority element in an array, say x, then it is okay to discard 
// a part of that array that has no majority element, the remaining array will still have
// x as the majority element

// worst case complexity :  O(n)

int findMajorityElement(int* arr, int size) { 
    int count = 0, i, majorityElement;
    for (i = 0; i < size; i++) {
        if (count == 0)
            majorityElement = arr[i];
        if (arr[i] == majorityElement) 
            count++;
        else
            count--;
    }
    count = 0;
    for (i = 0; i < size; i++)
        if (arr[i] == majorityElement)
            count++;
    if (count > size/2)
        return majorityElement;
    return -1;
}
Run Code Online (Sandbox Code Playgroud)

  • 这是摩尔的投票算法,应该归于正确. (13认同)
  • 这显然是最好的解决方案.这是流计数算法的一种特殊情况,其中仅跟踪一个元素.(您可以使用"n`"多数元素的集合来查找构成1 /(n + 1)或更多元素的任何元素.例如,使用9个多数元素,您会发现任何至少出现10个元素的元素% 的时间. (8认同)
  • 对于带有{2,1,2,4,1,2}的输入数组,此方法不应返回2.但它返回-1. (4认同)
  • @brainstorm:在大小为6的数组中,多数元素必须至少出现4次.在您的数组中,"2"仅出现3次. (3认同)
  • 伟大的解决方案,比接受的答案好得多! (2认同)
  • 如果大多数是-1怎么办? (2认同)

Sal*_*ali 37

令人遗憾的是,在5年内没有人为这个问题写过正确的解释.

这是流式算法中的标准问题(您有一个巨大的(可能无限的)数据流),您必须从此流计算一些统计信息,并通过此流一次.


显然,您可以使用散列或排序来处理它,但是如果有可能无限的流,您可以清楚地耗尽内存.所以你必须在这里做一些聪明的事情.


多数元素是发生超过数组大小一半的元素.这意味着多数元素的出现超过了所有其他元素的组合.也就是说,如果计算多数元素出现的次数,并减去所有其他元素的出现次数,您将得到一个正数.

因此,如果计算某个元素的出现次数,并减去所有其他元素的出现次数并得到数字0 - 那么原始元素不能是多数元素.这是正确算法的基础:

声明两个变量counter和possible_element.迭代流,如果计数器为0 - 你覆盖可能的元素并初始化计数器,如果数字与可能元素相同 - 增加计数器,否则减少它.Python代码:

def majority_element(arr):
    counter, possible_element = 0, None
    for i in arr:
        if counter == 0:
            possible_element, counter = i, 1
        elif i == possible_element:
            counter += 1
        else:
            counter -= 1

    return possible_element
Run Code Online (Sandbox Code Playgroud)

很明显,算法O(n)之前的常数非常小O(n)(如3).它看起来像空间复杂度O(1),因为我们只有三个变量初始化.问题是这些变量之一是一个可能长大的计数器n(当数组由相同的数字组成时).并存储n您需要O(log (n))空间的数字.所以从理论的角度来看它是O(n)时间和O(log(n))空间.从实际情况来看,你可以在longint中拟合2 ^ 128个数字,并且数组中的这些元素数量难以想象.

另请注意,只有存在多数元素时,算法才有效.如果这样的元素不存在,它仍然会返回一些数字,这肯定是错误的.(很容易修改算法来判断多数元素是否存在)

历史频道:这个算法是1982年由Boyer,Moore发明的,并称为Boyer-Moore多数投票算法


Axn*_*Axn 26

多数元素(如果存在)也将是中位数.我们可以在O(n)中找到中位数,然后检查它确实是O(n)中的有效多数元素.更多实施链接的细节

  • 技术上正确,但O(N)具有非常高的常数因子. (11认同)
  • @marcog 确实。但当面试官拒绝最佳解决方案时,你必须发挥创意:) (2认同)
  • @marcog我看到的两个链接要么提到了OP的算法本身,要么提到了概率算法.在这种情况下,两者都不会被接受. (2认同)
  • 此解决方案的问题在于它需要额外的假设,即元素上存在全序。尽管这在整数示例中是令人满意的,但通常元素不一定具有可比性。有一个解决方案只需要测试相等性,而不是顺序。 (2认同)

Adi*_*tya 16

多数元素:

大小为n的数组A []中的多数元素是一个出现超过n/2次的元素(因此最多只有一个这样的元素).

寻找候选人:

在O(n)中工作的第一阶段算法称为摩尔投票算法.算法的基本思想是,如果我们用e的所有其他元素抵消元素e的每次出现,那么如果它是多数元素,则e将存在直到结束.

findCandidate(a[], size)
1.  Initialize index and count of majority element
     maj_index = 0, count = 1
2.  Loop for i = 1 to size – 1
    (a)If a[maj_index] == a[i]
        count++
    (b)Else
        count--;
    (c)If count == 0
        maj_index = i;
        count = 1
3.  Return a[maj_index]
Run Code Online (Sandbox Code Playgroud)

上面的算法循环遍历每个元素并保持[maj_index]的计数,如果下一个元素相同则增加计数,如果下一个元素不相同则减少计数,如果计数达到0则将maj_index更改为当前element和sets count为1. First Phase算法为我们提供了候选元素.在第二阶段,我们需要检查候选人是否真的是多数元素.

第二阶段很简单,可以在O(n)中轻松完成.我们只需要检查候选元素的数量是否大于n/2.

阅读geeksforgeeks了解更多详情