找到数组中的多数元素

时间:2010-12-01 14:11:01

标签: arrays algorithm time-complexity

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

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

示例输入:

{2,1,2,3,4,2,1,2,2}

预期产出:

2

21 个答案:

答案 0 :(得分:107)

// 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;
}

答案 1 :(得分:33)

这是悲伤地看到,在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

很明显,算法O(n)O(n)之前具有非常小的常数(如3)。此外,空间复杂度似乎为O(1),因为我们只初始化了三个变量。问题是这些变量之一是一个可能长到n的计数器(当数组由相同的数字组成时)。要存储您需要n空格的O(log (n))号码。从理论的角度来看 它是O(n)时间和O(log(n))空间。 从实际开始,你可以在longint中输入2 ^ 128个数字,并且数组中的元素数量难以想象。

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

历史频道:这个算法是1982年由Boore,Moore在某处发明的,并称为Boyer–Moore majority vote algorithm

答案 2 :(得分:26)

多数元素(如果存在)也将是中位数。我们可以在O(n)中找到中位数,然后检查它确实是O(n)中的有效多数元素。 有关实施的更多详细信息link

答案 3 :(得分: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]

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

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

阅读geeksforgeeks了解更多详情

答案 4 :(得分:4)

时间:O(n)的

空间:O(n)的

遍历树并计算哈希表中元素的出现次数。

时间:O(n lg n)或O(n * m)(取决于使用的种类)

空间:(1)

对数组进行排序,然后计算元素的出现次数。

采访正确答案:摩尔的投票算法

时间:O(n)

空间:O(1)

走列表比较当前数字与当前最佳猜测数字。如果数字等于当前最佳猜测数增加一个计数器,否则递减计数器,如果计数器达到零,则用当前数字替换当前最佳猜测数,并将计数器设置为1.当你到达结束时最好的猜测是候选人号码,再次列出候选人的实例。如果最终计数大于n / 2,那么它是多数,否则没有一个。

答案 5 :(得分:3)

随机抽样方法怎么样?您可以对sqrt(n)元素进行采样,对于发生超过sqrt(n)/ 4次的每个元素(可以在O(n)时间和O(sqrt(n))空间中天真地完成),您可以检查是否是O(n)时间的多数元素。

该方法以高概率找到多数,因为多数元素的期望值至少为sqrt(n)/ 2倍,标准差最大为n ^ {1/4} / 2。

另一种类似于我在其中一个重复链接中看到的方法的采样方法是绘制两个样本,如果它们相等,则验证您在O(n)时间内找到了多数元素。额外的验证步骤是必要的,因为除了大多数之外的其他元素可能不是不同的。

答案 6 :(得分:2)

在蒙特卡罗算法中,

Majority (a,n)
//a[]-array of 'n' natural numbers
 {
  j=random(0,1,....,n-1)
  /*Selecting the integers at random ranging from 0 to n-1*/
  b=a[j];c=0;
  for k from 0 to n-1 do
   { 
    if a[k]=b then,
    c=c+1;
    }
    return (c>n/2)
   }

答案 7 :(得分:1)

要查找数组中的大部分元素,您可以使用摩尔的多数投票算法,这是最好的算法之一。

时间复杂度: O(n) or linear time

空间复杂性: O(1) or constant space

Moore's Majority Vote AlgorithmGeeksforGeeks

了解详情

答案 8 :(得分:0)

多数元素是出现超过⌊n / 2⌋次的元素。

输入:nums = [3,2,2,2,3]

输出:2

Python 代码:

def majorityElement(nums):
    nums.sort() or nums = sorted(nums)
    return nums[len(nums)//2]

nums = [int(x) for x in input()]
print(majorityElements(nums))

答案 9 :(得分:0)

O(n*logn)时间找到多数元素

  1. 多数元素至少出现(n / 2 +1)次(例如L等于该值),其中n是数组的大小。因此,显然2 * L> n。
  2. 因此,数组中不能有两个长度L的值不同的序列。
  3. 现在,对数组进行排序-如果您能够做到最好,则将花费O(n * logn)时间。
  4. 这是棘手的部分: 在排序的列表中,尝试在数组的开头到结尾之间对每个长度为L的序列加下划线。 即第一个序列的取值范围是0至L,第二个序列的取值范围是1至(L + 1),依此类推。 观察到在所有此类序列中,位于第L位的元素都是公用的。换句话说,如果存在多数元素,则它将始终位于中间值。 因此,我们可以得出结论,第L个位置的元素可以是候选关键字。

  5. 现在,计算元素在第L个位置的出现次数。如果其大于n / 2,那么瞧!您有答案,否则对不起,该数组不包含任何多数元素。

答案 10 :(得分:0)

public class MajorityElement {

   public static void main(String[] args) {
    Scanner sc = new Scanner(System.in);
    int testCases = sc.nextInt();
    while(testCases-- > 0) {
        int n = sc.nextInt();
        int a[] = new int[n];
        int maxCount = 0;
        int index = -1;
        for(int i = 0 ; i < n; i++) {
            a[i] = sc.nextInt();
        }
        for(int i = 0; i < n; i++) {
            int count =0;
            for(int j = 0; j < n; j++) {
                if(a[i] == a[j])
                    count++;
            }
            if(count > maxCount) {
                maxCount = count;
                index = i;
            }
        }
        if(maxCount > n/2)
            System.out.println(a[index]);
        else
            System.out.println(-1);
    }
    sc.close();
   }

}

答案 11 :(得分:0)

使用分而治之找到多数元素。如果我们将数组分为两半,则多数元素应为其中一半的多数。如果我们继续合并子数组,我们可以找出多数元素是否也是合并数组的大部分。具有O(nlogN)复杂性。

这是C ++实现:

#include <algorithm>
#include <iostream>
#include <vector>

using std::vector;

// return the count of elem in the array
int count(vector <int> &a, int elem, int low, int high)
{
    if (elem == -1) {
        return -1;
    }

    int num = 0;
    for (int i = low; i <= high; i++) {
        if (a[i] == elem) {
            num++;
        }
    }

    return num;
}

// return the majority element of combined sub-array. If no majority return -1
int combined(vector <int> &a, int maj1, int maj2, int low, int mid, int high)
{
    // if both sub arrays have same majority elem then we can safely say
    // the entire array has same majority elem.
    // NOTE: No majority ie. -1 will be taken care too
    if (maj1 == maj2) {
        return maj1;
    }

    // Conflicting majorities
    if (maj1 != maj2) {
        // Find the count of each maj1 and maj2 in complete array
        int num_maj1 = count(a, maj1, low, high);
        int num_maj2 = count(a, maj2, low, high);
        if (num_maj1 == num_maj2) {
            return -1;
        }
        int half = (high - low + 1) / 2;
        if (num_maj1 > half) {
            return maj1;
        } else if (num_maj2 > half) {
            return maj2;
        }
    }
    return -1;
}

// Divide the array into 2 sub-arrays. If we have a majority element, then it
// should be a majority in at least one of the half. In combine step we will
// check if this majority element is majority of the combination of sub-arrays.
// array a and low is lower index and high is the higher index of array
int get_majority_elem(vector<int> &a, int low, int high)
{
  if (low > high) return -1;
  if (low == high) return a[low];

  int mid = (low + high) / 2;

  int h1 = get_majority_elem(a, low, mid);
  int h2 = get_majority_elem(a, mid + 1, high);

  // calculate the majority from combined sub arrays
  int me = combined(a, h1, h2, low, mid, high);
  return me;
}

答案 12 :(得分:0)

这就是我在C ++中使用矢量和多图(带有重复键的JSON)的方法。

var Content = "nickname:Steven ID:01 nickname:pascal ID:02 nickname:nils ID:03";
var list = Regex.Matches(Content, @"nickname:(.+?)\s+ID:(\d+)")
            .Cast<Match>()
            .Select(m => new
            {
                Name = m.Groups[1].Value,
                ID = m.Groups[2].Value
            })
            .ToList();

答案 13 :(得分:0)

这将帮助您,如果两个元素重复相同的次数,如果不显示。

int findCandidate(int a[], int size)
{
int count,temp=0,i,j, maj;

for (i = 0; i < size; i++) {
count=0;      
for(j=i;j<size;j++)
{
    if(a[j]==a[i])
    count++;
}
if(count>temp)
{   
    temp=count;
    maj=i;
}
else if(count==temp)
{   
    maj=-1; 
}
}


return maj;
}

答案 14 :(得分:0)

//假设我们得到一个数组A. //如果我们拥有给定数组中的所有元素,这样每个元素都小于K,那么我们就可以创建一个长度为K + 1的附加数组B.

//使用0初始化数组的每个索引处的值。 //然后遍历给定的数组A,对于每个数组值A [i],在创建的数组B中相应的索引A [i]处将值递增1。

//在遍历数组A之后,现在迭代数组B并找到最大值。如果您发现该值大于n / 2,则返回该特定索引。

//如果K <= n则等于O(n),时间复杂度将为O(n + K)。

//这里我们有一个约束,即数组的所有元素都是O(K)。 //假设每个元素小于或等于100,在这种情况下K为100。

import javax.print.attribute.standard.Finishings;
public class MajorityElement {

    private static int maxElement=100;

    //Will have all zero values initially
    private static int arrB[]=new int[maxElement+1];
    static int findMajorityElement(int[] arrA) { 
         int count = 0, i, majorityElement;
         int n=arrA.length;
         for (i = 0; i < n; i++) {
             arrB[arrA[i]]+=1;
         }

         int maxElementIndex=1;
         for (i = 2; i < arrB.length; i++){
             if (arrB[i]>n/2) {
                maxElementIndex=i;
                break;
            }
        }
        return maxElementIndex;
    }`

    public static void main(String[] args) {
         int arr[]={2,6,3,2,2,3,2,2};
         System.out.println(findMajorityElement(arr));
    }
}

答案 15 :(得分:0)

感谢之前的回答,这让我了解Bob Boyer's algo.:)

Java通用版本:Boyer算法的修改版本

注意:基本类型数组可以使用包装器。

import com.sun.deploy.util.ArrayUtil;
import com.sun.tools.javac.util.ArrayUtils;

/**
 * Created by yesimroy on 11/6/16.
 */
public class FindTheMajority {

/**
 *
 * @param array
 * @return the value of the majority elements
 */
public static <E> E findTheMajority(E[] array){
    E majority =null;
    int count =0;

    for(int i=0; i<array.length; i++){
        if(count==0){
            majority = array[i];
        }
        if(array[i].equals(majority)){
            count++;
        }else{
            count--;
        }

    }

    count = 0;
    for(int i=0; i<array.length ; i++){
        if(array[i].equals(majority)){
            count++;
        }
    }

    if(count > (array.length /2)){
        return majority;
    }else{
        return null;
    }
}

public static void main(String[] args){
    String[] test_case1 = {"Roy","Roy","Roy","Ane","Dan","Dan","Ane","Ane","Ane","Ane","Ane"};
    Integer[] test_case2 = {1,3,2,3,3,3,3,4,5};

    System.out.println("test_case1_result:" + findTheMajority(test_case1));
    System.out.println("test case1 the number of majority element should greater than" + test_case1.length/2);
    System.out.println();

    System.out.println("test_case2_result:" + findTheMajority(test_case2));
    System.out.println("test case2 the number of majority element should greater than" + test_case2.length/2);
    System.out.println();
}

}

答案 16 :(得分:0)

修改版Boyer的算法

  • 3通过,其中,
    • 在第一遍中,我们进行数组的正向迭代
    • 在第二遍中,我们对数组进行反向迭代。
    • 在第三次传球中,获得在第一次和第二次传球中获得的多数元素的计数。

技术上是线性复杂度算法(O(3n))。 我相信这应该适用于一个多数元素至少发生n / 2次的数组。

#include <iostream>
#include <vector>

template <typename DataType>
DataType FindMajorityElement(std::vector<DataType> arr) {
    // Modified BOYERS ALGORITHM with forward and reverse passes
    // Count will stay positive if there is a majority element
    auto GetMajority = [](auto seq_begin, auto seq_end) -> DataType{
        int count = 1;
        DataType majority = *(seq_begin);
        for (auto itr = seq_begin+1; itr != seq_end; ++itr) {
            count += (*itr == majority) ? 1 : -1;
            if (count <= 0) {   // Flip the majority and set the count to zero whenever it falls below zero
                majority = *(itr);
                count = 0;
            }
        }
        return majority;
    };
    DataType majority1 = GetMajority(arr.begin(), arr.end());
    DataType majority2 = GetMajority(arr.rbegin(), arr.rend());
    int maj1_count = 0, maj2_count = 0;
    // Check if any of the the majority elements is really the majority
    for (const auto& itr: arr) {
        maj1_count += majority1 == itr ? 1 : 0;
        maj2_count += majority2 == itr ? 1 : 0;
    }
    if (maj1_count >= arr.size()/2)
        return majority1;
    if (maj2_count >= arr.size()/2)
        return majority2;
    // else return -1
    return -1;
}

Code tested here

答案 17 :(得分:0)

public class MajorityElement
    {
       public static void main(String[] args) 
          {
             int arr[]={3,4,3,5,3,90,3,3};

              for(int i=0;i<arr.length;i++)
                {
                  int count=0;
                   int j=0;

                    while(j<arr.length-1)
                     { 
                        if(i==j)
                        j=j+1;
                          if(arr[i]==arr[j])
                            count++;
                          j++;
                                  }

                             if(count>=arr.length/2)
                               {
                              System.out.println("majority element"+arr[i]);
                                   break;
    }
    }


}

}

答案 18 :(得分:0)

startForeground()

时间复杂度O(n)

答案 19 :(得分:0)

如果允许您创建哈希表并假设哈希条目查找是常量,则只需针对出现次数对每个条目进行hash_map。

您可以通过表格进行第二次传递,获得计数最高的那个,但如果您事先知道表格中的元素数量,您将立即知道我们是否在第一次传递时拥有多数元素我们在元素上达到了所需的计数。

当然,您无法保证连续2次出现该元素,例如1010101010101010101没有连续的1,但它是多数元素。

我们没有被告知任何关于元素类型是否有任何排序的事情,尽管显然我们必须能够比较两个是否相等。

答案 20 :(得分:-4)

对给定数组进行排序:O(nlogn)。

如果数组大小为7,那么多数元素在数组中出现至少上限(7/2)= 4次。

对数组进行排序后,意味着如果首先在位置i找到多数元素,则在位置i + floor(7/2)处找到它(4次出现)。

示例 - 给定数组A - {7,3,2,3,3,6,3}

对数组进行排序 - {2,3,3,3,3,6,7}

元素3位于第1位(数组索引从0开始)。如果位置1 + 3 =第4个元素也是3,则表示3是多数元素。

如果我们从头开始遍历数组..

比较位置0和位置3,不同的元素2和3。 比较位置1和位置4,相同的元素。我们找到了多数匹配!

复杂性 - O(n)

总时间复杂度 - O(n)。

相关问题