L'élément majoritaire est l'élément qui apparaît plus de la moitié de la taille du tableau.
Comment trouver l'élément majoritaire dans un tableau dans O(n)
?
Exemple d'entrée:
{2,1,2,3,4,2,1,2,2}
Production attendue:
2
L'élément majoritaire (s'il existe) sera également la médiane. Nous pouvons trouver la médiane dans O(n), puis vérifier qu’il s’agit bien d’un élément majoritaire valide dans O (n) . Plus de détails pour la mise en œuvre lien
// 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;
}
Il est regrettable de constater qu’en 5 ans, personne n’a écrit une explication appropriée à ce problème.
C'est un problème standard dans les algorithmes de flux (où vous avez un flux de données énorme (potentiellement infini)) et vous devez calculer des statistiques à partir de ce flux, en passant par ce flux une fois.
Clairement, vous pouvez l'aborder avec un hachage ou un tri, mais avec un flux potentiellement infini, vous pouvez clairement manquer de mémoire. Donc, vous devez faire quelque chose d'intelligent ici.
L'élément majoritaire est l'élément qui apparaît plus de la moitié de la taille du tableau. Cela signifie que l’élément majoritaire apparaît plus que tous les autres éléments combinés. Autrement dit, si vous comptez le nombre de fois où l'élément majoritaire apparaît et soustrayez le nombre d'occurrences de tous les autres éléments, vous obtiendrez un nombre positif.
Donc, si vous comptez les occurrences d'un élément et soustrayez le nombre d'occurrences de tous les autres éléments et obtenez le nombre 0, votre élément d'origine ne peut pas être un élément majoritaire. Ceci est la base pour un algorithme correct:
Déclarez deux variables, counter et possible_element. Itérez le flux si le compteur est à 0 - écrasez l'élément possible et initialisez le compteur si le nombre est identique à l'élément possible - augmentez le compteur, sinon réduisez-le. Code 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
Il est clair que l'algorithme est O(n)
avec une très petite constante avant O(n)
(comme 3). En outre, il semble que la complexité de l'espace soit O(1)
, car nous n'avons initialisé que trois variables. Le problème est qu’une de ces variables est un compteur qui peut potentiellement atteindre n
(lorsque le tableau est composé des mêmes nombres). Et pour stocker le nombre n
, vous avez besoin de O(log (n))
espace. Donc, du point de vue théorique, il s'agit de O(n)
time et de O(log(n))
space. De pratique, vous pouvez insérer un nombre 2 ^ 128 dans un entier long et ce nombre d'éléments dans le tableau est incroyablement énorme.
Notez également que l'algorithme ne fonctionne que s'il existe un élément majoritaire. Si un tel élément n'existe pas, il retournera quand même un nombre, ce qui sera sûrement faux. (il est facile de modifier l'algorithme pour savoir si l'élément majoritaire existe)
Canal Histoire: cet algorithme a été inventé quelque part en 1982 par Boyer et Moore et appelé Algorithme de vote majoritaire Boyer – Moore
_ {Elément majoritaire:} _
Un élément majoritaire dans un tableau A [] de taille n est un élément qui apparaît plus de n/2 fois (et il existe donc au plus un de ces éléments).
_ {Trouver un candidat: _
L’algorithme de la première phase qui fonctionne dans O(n) est appelé algorithme de vote de Moore. L'idée de base de l'algorithme est que si nous annulons chaque occurrence d'un élément e avec tous les autres éléments différents de e, e existera jusqu'à la fin s'il s'agit d'un élément majoritaire.
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]
L'algorithme ci-dessus parcourt chaque élément et conserve le nombre d'un [maj_index]. Si l'élément suivant est identique, le compte est incrémenté; si l'élément suivant n'est pas identique, il est décrémenté et si le nombre atteint 0, le maj_index est remplacé par le nombre actuel. element et définit count à 1 . L'algorithme de première phase nous donne un élément candidat. Dans une deuxième phase, nous devons vérifier si le candidat est réellement un élément majoritaire.
Deuxième phase est simple et peut être facilement réalisé en O (n). Il suffit de vérifier si le nombre d'éléments candidats est supérieur à n/2.
Lire geeksforgeeks pour plus de détails
Il est temps)
Espace: O (n)
Parcourez l’arbre et comptez l’occurrence d’éléments dans une table de hachage.
Temps: O (n lg n) ou O (n * m) (dépend de la sorte utilisée)
espace: (1)
trier le tableau puis compter les occurrences des éléments.
La réponse correcte de l’entrevue: Algorithme de vote de Moore
Il est temps)
Espace: O (1)
Parcourez la liste pour comparer le nombre actuel par rapport au meilleur chiffre estimé. Si le nombre est égal au meilleur chiffre estimé actuel, incrémentez un compteur, sinon décrémentez-le et si le compteur atteint zéro, remplacez le numéro actuel par le nombre actuel et réglez le compteur sur 1. Lorsque vous arrivez à la fin du La meilleure hypothèse est le numéro du candidat, parcourez à nouveau la liste en ne comptant que les instances du candidat. Si le nombre final est supérieur à n/2, il s'agit du nombre majoritaire, sinon il n'en existe pas.
En algorithme de Monte-Carlo,
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)
}
Que diriez-vous d'une approche d'échantillonnage aléatoire? Vous pouvez échantillonner, par exemple, les éléments sqrt (n) et pour chaque élément survenu plus de sqrt (n)/4 fois (peut être accompli naïvement dans O(n) time et O(sqrt(n)) space), vous pouvez vérifier s’il s’agit d’un élément majoritaire dans O(n) time.
Cette méthode trouve la majorité avec une probabilité élevée parce que l'élément majoritaire serait échantillonné au moins sqrt (n)/2 fois en attente, avec un écart-type d'au plus n ^ {1/4}/2.
Une autre approche d'échantillonnage similaire à celle que j'ai vue dans l'un des liens en double consiste à tirer deux échantillons et, s'ils sont égaux, vérifiez que vous avez trouvé l'élément majoritaire dans O(n) time. L'étape de vérification supplémentaire est nécessaire car les autres éléments, à part la majorité, peuvent ne pas être distincts.
Pour trouver la majorité d'un élément dans un tableau, vous pouvez utiliser l'algorithme de vote majoritaire de Moore, qui est l'un des meilleurs algorithmes pour ce dernier.
Complexité temporelle:O(n) or linear time
Complexité de l'espace:O(1) or constant space
Lire la suite sur L'algorithme de vote majoritaire de Moore et GeeksforGeeks
Une version modifiée de l'algorithme de Boyer,
Techniquement, un algorithme de complexité linéaire (O (3n)) . Je pense que cela devrait fonctionner pour un tableau avec un élément majoritaire qui apparaît au moins n/2 fois.
#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;
}
Utilisez Diviser pour conquérir pour trouver l’élément majoritaire. Si nous divisons le tableau en deux moitiés, l’élément majoritaire devrait être majoritaire dans l’une des moitiés. Si nous combinons les sous-tableaux, nous pourrons déterminer si l'élément majoritaire est également la majorité du tableau combiné. Cela a une complexité O (nlogN).
Voici une implémentation 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;
}
// Supposons qu'on nous donne un tableau A ..__ // // si nous avons tous les éléments du tableau donné tels que chaque élément soit inférieur à K, nous pouvons créer un tableau supplémentaire B de longueur K + 1.
// Initialise la valeur à chaque index du tableau avec 0. // Puis itérons dans le tableau donné A, pour chaque valeur de tableau A [i], incrémentez la valeur de 1 à l'index correspondant A [i] dans le tableau créé B.
// Après avoir parcouru le tableau A, parcourez maintenant le tableau B et recherchez la valeur maximale. Si vous trouvez la valeur supérieure à n/2, renvoyez cet index particulier.
// La complexité temporelle sera O (n + K) si K <= n alors équivalent à O (n).
// Nous avons une contrainte ici que tous les éléments du tableau sont O (K). // En supposant que chaque élément est inférieur ou égal à 100, dans ce cas, K est égal à 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));
}
}
Cela vous aidera et si deux éléments se répètent le même nombre de fois si aucun ne sera affiché.
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;
}
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;
}
}
}
}
Voici comment je le fais en C++ en utilisant des vecteurs et des cartes multiples (JSON avec des clés de répétition).
#include <iostream>
#include <vector>
#include <algorithm>
#include <map>
#include <iterator>
using namespace std;
vector <int> majorityTwoElement(vector <int> nums) {
// declare variables
multimap <int, int> nums_map;
vector <int> ret_vec, nums_unique (nums);
int count = 0;
bool debug = false;
try {
// get vector of unique numbers and sort them
sort(nums_unique.begin(), nums_unique.end());
nums_unique.erase(unique(nums_unique.begin(), nums_unique.end()), nums_unique.end());
// create map of numbers and their count
for(size_t i = 0; i < nums_unique.size(); i++){
// get number
int num = nums_unique.at(i);
if (debug) {
cout << "num = " << num << endl;
}
// get count of number
count = 0; // reset count
for(size_t j = 0; j < nums.size(); j++) {
if (num == nums.at(j)) {
count++;
}
}
// insert number and their count into map (sorted in ascending order by default)
if (debug) {
cout << "num = " << num << "; count = " << count << endl;
}
nums_map.insert(pair<int, int> (count, num));
}
// print map
if (debug) {
for (const auto &p : nums_map) {
cout << "nums_map[" << p.first << "] = " << p.second << endl;
}
}
// create return vector
if (!nums_map.empty()) {
// get data
auto it = prev(nums_map.end(), 1);
auto it1 = prev(nums_map.end(), 2);
int last_key = it->first;
int second_last_key = it1->first;
// handle data
if (last_key == second_last_key) { // tie for repeat count
ret_vec.Push_back(it->second);
ret_vec.Push_back(it1->second);
} else { // no tie
ret_vec.Push_back(it->second);
}
}
} catch(const std::exception& e) {
cerr << "e.what() = " << e.what() << endl;
throw -1;
}
return ret_vec;
}
int main() {
vector <int> nums = {2, 1, 2, 3, 4, 2, 1, 2, 2};
try {
// get vector
vector <int> result = majorityTwoElement(nums);
// print vector
for(size_t i = 0; i < result.size(); i++) {
cout << "result.at(" << i << ") = " << result.at(i) << endl;
}
} catch(int error) {
cerr << "error = " << error << endl;
return -1;
}
return 0;
}
// g++ test.cpp
// ./a.out
Merci pour les réponses précédentes qui m'ont inspiré pour savoir Algo de Bob Boyer. :)
Version générique Java: Une version modifiée de l'algorithme de Boyer
Remarque: un tableau de type primitif pourrait utiliser un wrapper.
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();
}
}
Si vous êtes autorisé à créer une table de hachage et en supposant que la recherche d'entrée de hachage est constante, vous devez seulement hash_map chaque entrée par rapport au nombre d'occurrences.
Vous pouvez faire un second passage dans la table pour obtenir celui avec le compte le plus élevé, mais si vous connaissez à l'avance le nombre d'éléments dans la table, vous saurez immédiatement si nous avons un élément majoritaire lors du premier passage lorsque nous atteignons le requis compter sur l'élément.
Vous ne pouvez certes pas garantir qu’il existe même une séquence de 2 occurrences consécutives de l’élément, par exemple 1010101010101010101 n’a pas de 1 consécutif mais c’est un élément majoritaire.
On ne nous dit rien sur le fait qu'il y ait un quelconque ordre dans le type d'élément, bien que nous devions évidemment pouvoir en comparer deux pour l'égalité.
int majorityElement(int[] num) {
int major=num[0], count = 1;
for(int i=1; i<num.length;i++){
if(count==0){
count++;
major=num[i];
}
else if(major==num[i]){
count++;
}
else
count--;
}
return major;
}
Complexité temporelle O(n)