Wie finde ich das Element eines Arrays, das mindestens N/2 Mal wiederholt wird?

Lesezeit: 7 Minuten

Benutzeravatar von Flash
Blinken

Gegeben sei ein Array mit N Elementen. Wir wissen, dass sich eines dieser Elemente mindestens N/2 Mal wiederholt.

Über die anderen Elemente wissen wir nichts. Sie können sich wiederholen oder einmalig sein.

Gibt es eine Möglichkeit, das Element herauszufinden, das sich mindestens N/2 Mal in einem einzigen Durchgang wiederholt oder O (N) sein kann?

Es darf kein zusätzlicher Platz verwendet werden.

  • Ist das eine Hausaufgabe? Wenn ja, kennzeichnen Sie es bitte als solches.

    – Wird A

    18. September 2010 um 4:25 Uhr

  • Es kann kein zusätzlicher Speicherplatz verwendet werden, oder es kann nur O(1)-Speicherplatz verwendet werden? Das Iterieren über ein Array muss etwas Platz beanspruchen.

    – Wird A

    18. September 2010 um 4:26 Uhr


  • @ Will: Es ist keine Hausaufgabe … Ich habe es genug versucht, konnte aber keinen besseren Weg finden …

    – Blinken

    18. September 2010 um 4:30 Uhr

  • Streng genommen lässt sich dieses Problem nicht lösen O(1) Raum, weil die Sprache nicht regulär ist. Die für eine beliebige Lösung erforderliche Zählervariable dauert O(log n) Platz. 🙂

    – R.. GitHub HÖR AUF, EIS ZU HELFEN

    18. September 2010 um 12:41 Uhr

  • @R.. : Das ist technisch korrekt….das Beste irgendwie richtig!

    – Jim Lewis

    18. September 2010 um 23:24 Uhr

Da die anderen Benutzer den Algorithmus bereits gepostet haben, werde ich das nicht wiederholen. Ich gebe jedoch eine einfache Erklärung, warum es funktioniert:

Betrachten Sie das folgende Diagramm, das eigentlich ein Diagramm von unpolarisiertem Licht ist:

Pfeile, die von der Mitte ausgehen

Jeder Pfeil von der Mitte repräsentiert einen anderen Kandidaten. Stellen Sie sich einen Punkt irgendwo auf einem Pfeil vor, der den Zähler und den Kandidaten darstellt. Anfangs steht der Zähler auf Null, also beginnt er in der Mitte.
Wenn der aktuelle Kandidat gefunden ist, bewegt er sich einen Schritt in Richtung dieses Pfeils. Wird ein anderer Wert gefunden, bewegt sich der Zähler einen Schritt in Richtung Mitte.
Wenn es einen Mehrheitswert gibt, werden mehr als die Hälfte der Bewegungen in Richtung dieses Pfeils gehen, und daher wird der Algorithmus damit enden, dass der aktuelle Kandidat der Mehrheitswert ist.

Benutzeravatar von David Titarenco
David Titarenco

st0le hat die Frage beantwortet, aber hier ist eine 5-Minuten-Implementierung:

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

Und hier ist eine lustige Erklärung (mehr Spaß als das Lesen der Zeitung zumindest): http://userweb.cs.utexas.edu/~moore/best-ideas/mjrty/index.html

  • Vielen Dank! Ganz schöne Idee. (Übrigens, Sie würden sicherlich noch mehr Upvotes bekommen, wenn Sie das Konzept allen in einfachem Englisch erklären würden. Es ist überhaupt nicht schwierig.)

    – Nikita Rybak

    18. September 2010 um 4:59 Uhr


  • Dieser Algorithmus erfüllt die Bedingungen der Frage. Man sollte jedoch bedenken, dass es das potenzielle Mehrheitselement zurückgibt. Wenn es keine Mehrheit gibt, dann ist das Ergebnis bedeutungslos. Wenn Sie sich also nicht sicher sind, müssen Sie eine zweite Schleife durchlaufen und sehen, wie oft dieses Element tatsächlich vorkommt.

    – Matthew

    18. September 2010 um 5:03 Uhr


  • Die Frage setzt das voraus we know that one of those elements repeats itself *at least* N/2 times Wenn also die Daten wohlgeformt sind, funktioniert der Algorithmus jedes Mal.

    – David Titarenco

    18. September 2010 um 5:04 Uhr

  • +1 für einen Link zu einer hervorragenden Erklärung eines brillanten Algorithmus, den ich noch nie zuvor gesehen habe.

    – Mark Rushakoff

    18. September 2010 um 5:45 Uhr

  • @David, es ist möglicherweise falsch, wenn Sie einen neuen Kandidaten zuweisen, sollte Ihre Zählung zugewiesen werden =1

    – Stil

    19. September 2010 um 6:02 Uhr


Benutzeravatar von st0le
Stil

Der Boyer-Moore Mehrheitsabstimmungsalgorithmus

//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)

  • Es ist ziemlich einfach, Sie könnten es leicht implementieren.

    – Stil

    18. September 2010 um 4:28 Uhr

  • ziemlich einfach Möchtest du es dem Rest von uns erklären?

    – Nikita Rybak

    18. September 2010 um 4:39 Uhr

  • Eine Antwort mit einer einfachen Implementierung hinzugefügt.

    – David Titarenco

    18. September 2010 um 4:52 Uhr

  • @st0le: Dein Beispiel ist nicht korrekt. Sie verwenden den Index i anstelle des Listenwerts lst[i] sowohl im Vergleich als auch in der Zuordnung. Könntest du es reparieren?

    – Harfner

    18. September 2010 um 7:46 Uhr

  • @Harper, i enthält den Wert selbst … ich denke, i Die Konvention hat dich aus der Bahn geworfen. Ich werde es umbenennen.

    – Stil

    18. September 2010 um 8:39 Uhr

Benutzeravatar von coder101
coder101

Dieser Code ist eine ähnliche Implementierung wie wir den Großteil eines Elements finden

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

Es scheint nicht möglich zu sein, etwas zu zählen, ohne zusätzlichen Platz zu verwenden. Sie müssen mindestens einen Zähler irgendwo speichern. Wenn Sie sagen wollen, dass Sie nicht mehr als O (n) Speicherplatz verwenden können, sollte es ziemlich einfach sein.

Eine Möglichkeit wäre, eine zweite Liste nur mit eindeutigen Objekten aus der ursprünglichen Liste zu erstellen. Erstellen Sie dann eine dritte Liste mit der gleichen Länge wie die zweite mit einem Zähler für die Anzahl der Vorkommen jedes Elements in der Liste.

Eine andere Möglichkeit wäre, die Liste zu sortieren und dann den größten zusammenhängenden Abschnitt zu finden.

  • +1 – wahrscheinlich nicht die optimale Lösung, aber O (n log n) für die sortierungsbasierte Lösung ist ein guter Kompromiss gegenüber der Komplexität anderer Methoden.

    – Wird A

    18. September 2010 um 4:34 Uhr

  • Du versuchst nicht zu zählen. Sie versuchen, eine Zahl zu finden, die mindestens die Hälfte der Zeit vorkommt.

    – MSN

    18. September 2010 um 5:12 Uhr

Benutzeravatar von shams
Schein

Unter Verwendung der von ffao vorgeschlagenen Änderung an Davi würde antworten:

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

  • +1 – wahrscheinlich nicht die optimale Lösung, aber O (n log n) für die sortierungsbasierte Lösung ist ein guter Kompromiss gegenüber der Komplexität anderer Methoden.

    – Wird A

    18. September 2010 um 4:34 Uhr

  • Du versuchst nicht zu zählen. Sie versuchen, eine Zahl zu finden, die mindestens die Hälfte der Zeit vorkommt.

    – MSN

    18. September 2010 um 5:12 Uhr

Benutzeravatar von Andrii Abramov
Andrii Abramov

Versuche dies :

#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";
}

  • Wie beantwortet dies das Problem. Dies zeigt Ihnen nur die Anzahl der Fünfer. Es findet nicht heraus, welche Zahl die meisten Wiederholungen hat.

    – NathanOliver

    22. Januar 2016 um 17:49 Uhr

1386460cookie-checkWie finde ich das Element eines Arrays, das mindestens N/2 Mal wiederholt wird?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy