Clasa a XII-a · Tehnici avansate: doi pointeri, căutare binară pe răspuns, stive monotoneRead in English

Element majoritar (Boyer-Moore) în C++

În engleză: Majority element (Boyer-Moore)

O(n)C++1763 de linii2 exemple

Ideea

Elementul majoritar apare de mai mult de n / 2 ori. Algoritmul de vot ține un candidat și un contor: o valoare egală cu candidatul crește contorul, una diferită îl scade, iar la contor 0 valoarea curentă devine candidat. Ideea: dacă „anulăm” perechi de valori diferite, majoritarul nu poate fi anulat complet. Prima trecere dă doar un candidat, așa că a doua trecere numără aparițiile lui și verifică dacă e chiar majoritar. Funcționează pentru valori oricât de mari (nu are nevoie de vector de frecvență).

Descrierea în engleză

The majority element appears more than n / 2 times. The voting algorithm keeps a candidate and a counter: a value equal to the candidate increases the counter, a different one decreases it, and when the counter is 0 the current value becomes the candidate. The idea: if we 'cancel out' pairs of different values, the majority cannot be cancelled completely. The first pass only gives a candidate, so a second pass counts its occurrences and checks that it really is the majority. It works for arbitrarily large values (no frequency array needed).

Complexitate
O(n) timp, O(1) memorie suplimentară
Clasa
Clasa a XII-a (Grade 12)

Exemple

Exemplul 1

Intrare

9
3 1 3 3 2 3 3 1 3

Ieșire așteptată

3
Exemplul 2

Intrare

4
1 2 1 2

Ieșire așteptată

nu exista

Codul C++

Codul complet, cu comentarii în română. Îl poți modifica liber și îl poți reseta oricând.

element-majoritar-boyer-moore.cpp
/*
 * Titlu: Element majoritar (Boyer-Moore)
 * Clasa: 12
 * Capitol: Tehnici avansate: doi pointeri, căutare binară pe răspuns, stive monotone
 * Descriere: Elementul majoritar apare de mai mult de n / 2 ori. Algoritmul de
 *            vot ține un candidat și un contor: o valoare egală cu candidatul
 *            crește contorul, una diferită îl scade, iar la contor 0 valoarea
 *            curentă devine candidat. Ideea: dacă „anulăm” perechi de valori
 *            diferite, majoritarul nu poate fi anulat complet. Prima trecere dă
 *            doar un candidat, așa că a doua trecere numără aparițiile lui și
 *            verifică dacă e chiar majoritar. Funcționează pentru valori oricât
 *            de mari (nu are nevoie de vector de frecvență).
 * Complexitate: O(n) timp, O(1) memorie suplimentară
 *
 * Exemplu
 * Intrare:
 * 9
 * 3 1 3 3 2 3 3 1 3
 * Ieșire: 3
 *
 * Exemplu
 * Intrare:
 * 4
 * 1 2 1 2
 * Ieșire: nu exista
 */
#include <iostream>
#include <vector>
using namespace std;

int main()
{
    int n;
    cin >> n;
    vector<long long> a(n);
    for (int i = 0; i < n; i++)
        cin >> a[i];

    long long candidat = 0;
    int contor = 0;
    for (int i = 0; i < n; i++)
    {
        if (contor == 0)
        {
            candidat = a[i];
            contor = 1;
        }
        else if (a[i] == candidat)
            contor++;
        else
            contor--;
    }
    int aparitii = 0;
    for (int i = 0; i < n; i++)
        if (a[i] == candidat)
            aparitii++;
    if (2 * aparitii > n)
        cout << candidat << '\n';
    else
        cout << "nu exista\n";
    return 0;
}

Rulează pe un g++ adevărat (C++17, -O2) prin Compiler Explorer. Programele trebuie să se termine repede: există o limită de timp.