web-dev-qa-db-fra.com

Comment trouver l'élément d'un tableau qui se répète au moins N/2 fois?

Étant donné un tableau avec N éléments. Nous savons qu'un de ces éléments se répète au moins N/2 fois.

Nous ne savons rien des autres éléments. Ils peuvent répéter ou peuvent être uniques. 

Existe-t-il un moyen de trouver l'élément qui se répète au moins N/2 fois en une seule passe ou qui peut être O (N)?

Aucun espace supplémentaire ne doit être utilisé.

33
Flash

st0le a répondu à la question, mais voici une implémentation de 5 minutes:

#include <stdio.h>

#define SIZE 13

int boyerMoore(int arr[]) {
    int current_candidate = arr[0], counter = 0, i;
    for (i = 0; i < SIZE; ++i) {
        if (current_candidate == arr[i]) {
            ++counter;
            printf("candidate: %i, counter: %i\n",current_candidate,counter);
        } else if (counter == 0) {
            current_candidate = arr[i];
            ++counter;
            printf("candidate: %i, counter: %i\n",current_candidate,counter);
        } else {
            --counter;
            printf("candidate: %i, counter: %i\n",current_candidate,counter);
        }
    }
    return current_candidate;
}

int main() {
    int numbers[SIZE] = {5,5,5,3,3,1,1,3,3,3,1,3,3};
    printf("majority: %i\n", boyerMoore(numbers));
    return 0;
}

Et voici une explication amusante (plus amusante que de lire le journal): http://userweb.cs.utexas.edu/~moore/best-ideas/mjrty/index.html

37
David Titarenco

Comme les autres utilisateurs ont déjà posté l'algorithme, je ne le répéterai pas. Cependant, je fournis une explication simple pour expliquer pourquoi cela fonctionne:

Considérez le diagramme suivant, qui est en réalité un diagramme de lumière non polarisée:

arrows radiating from the centre

Chaque flèche du centre représente un candidat différent. Imaginez un point quelque part sur une flèche représentant le compteur et le candidat. Initialement, le compteur est à zéro, il commence donc au centre.
Lorsque le candidat actuel est trouvé, il avance d’un pas dans le sens de la flèche. Si une valeur différente est trouvée, le compteur se déplace d'un pas vers le centre.
S'il y a une valeur majoritaire, plus de la moitié des déplacements seront dirigés vers cette flèche et, par conséquent, l'algorithme se terminera par le candidat actuel comme valeur majoritaire.

55
Nabb

L'algorithme de vote majoritaire Boyer-Moore

//list needs to have an element with a count of more than n/2 throughout itself for
//this algorithm to work properly at all times.

lst = [1,2,1,2,3,1,3,3,1,2,1,1,1]

currentCount = 0
currentValue = lst[0]
for val in lst:
   if val == currentValue:
      currentCount += 1
   else:
      currentCount -= 1

   if currentCount == 0:
      currentValue = val
      currentCount = 1


print(currentValue)
36
st0le

Ce code est une implémentation similaire à la façon dont nous trouvons la majorité d’un élément

int find(int* arr, int size)
{ 
int count = 0, i, m;
  for (i = 0; i < size; i++) 
  {
    if (count == 0)
        m = arr[i];
    if (arr[i] == m) 
        count++;
    else
        count--;
   }
    return m;
}
2
coder101

En utilisant la modification suggérée par ffao pour répondre à Davi:

public class MaxRepeated {

    public static void main(final String[] args) {
        maxRepeatedElement(new int[]{1, 2, 1, 2, 3, 2, 3, 1});
        maxRepeatedElement(new int[]{1, 2, 1, 2, 3, 1, 3, 1});
        maxRepeatedElement(new int[]{1, 2, 1, 2, 4, 1, 1, 3, 1, 3, 1});
        maxRepeatedElement(new int[]{1, 2, 1, 2, 2, 1, 2, 3, 1, 2, 1, 2});
    }

    private static int maxRepeatedElement(final int[] arr) {

        int current_candidate = arr[0];
        int previous_candidate = arr[0];
        int counter = 0, i;
        for (i = 0; i < arr.length; ++i) {
            if (current_candidate == arr[i]) {
                ++counter;
            } else if (counter == 0) {
                previous_candidate = current_candidate;
                current_candidate = arr[i];
                ++counter;
            } else {
                --counter;
            }
            System.out.printf("  candidate: %d, counter: %d\n", current_candidate, counter);
        }

        if (counter == 0) {
            System.out.printf(" possible: %d or %d with net freq %d \n", current_candidate, previous_candidate, counter);
            final int f1 = frequency(arr, current_candidate);
            final int f2 = frequency(arr, previous_candidate);
            final int halfLen = arr.length / 2 + (arr.length % 2 == 0 ? 0 : 1);
            if (f1 >= halfLen || f2 >= halfLen) {
                if (f1 > f2) {
                    System.out.printf("majority: %d with freq %d \n", current_candidate, f1);
                } else {
                    System.out.printf("majority: %d with freq %d \n", previous_candidate, f2);
                }
            } else {
                System.out.printf("NO majority! \n");
            }
        } else {
            System.out.printf("majority: %d with freq %d \n", current_candidate, frequency(arr, current_candidate));
        }
        return current_candidate;
    }

    private static int frequency(final int[] arr, final int candidate) {
        int counter = 0;
        for (int c : arr) {
            counter += candidate == c ? 1 : 0;
        }
        return counter;
    }
}
0
shams

Essaye ça :

#include<iostream>
using namespace std;
int main()
{
    int counter=0;
    int a[]={10, 11, 5, 27, 4, 2, 7, 5, 7, 11, 9, 5, 5, 4, 10, 7, 5, 3, 7, 5};
    for(int i = 0; i < 20; i++)
    {
        if(a[i]==5)
        counter++;
    }
    cout << "it appears " << counter << " times";
}
0
srikanth

Il ne semble pas possible de compter quoi que ce soit sans utiliser davantage d'espace. Vous devez stocker au moins un compteur quelque part. Si vous voulez dire que vous ne pouvez pas utiliser plus de O(n) espace, alors cela devrait être assez facile. 

Une solution serait de créer une seconde liste d’objets uniques à partir de la liste d’origine. Créez ensuite une troisième liste de la même longueur que la deuxième avec un compteur du nombre d’occurrences de chaque élément de la liste.

Une autre solution consisterait à trier la liste, puis à trouver la plus grande section contiguë.

0
Puddingfox