De ce contează?
La o alegere, doi susținători ai unor candidați diferiți se anulează reciproc și pleacă acasă. Dacă un candidat are mai mulți susținători decât toți ceilalți la un loc, vor rămâne în sală doar oameni de-ai lui — oricât de multe anulări ar avea loc. Așa găsești majoritarul fără să numeri tot.
Ce este elementul majoritar?
Într-un vector cu n elemente, majoritarul e valoarea care apare strict de mai mult de n/2 ori. Dacă există, e unic — două valori cu peste n/2 apariții ar depăși împreună n elemente.
Exemplu: v = {2, 2, 1, 2, 3, 2, 2}, n = 7. Valoarea 2 apare de 5 ori (5 > 3), deci e majoritară.
Soluția simplă cu vector de frecvență
Dacă valorile sunt mici, numeri aparițiile într-un vector frecv și cauți una cu frecv[x] > n/2. Costă O(n) timp și O(valoare_maximă) spațiu. Funcționează, dar consumă memorie când valorile sunt mari.
Algoritmul de vot Boyer-Moore — O(1) memorie
Ideea: ții un candidat și un contor.
- Contor
0→ candidat nou = elementul curent, contor1. - Element egal cu candidatul → contor
+1. - Element diferit → contor
-1(o anulare reciprocă).
La final, candidatul rămas e singurul posibil majoritar.
Fiecare element diferit „anulează" o apariție a candidatului. Dacă majoritarul apare de peste n/2 ori, are mai multe apariții decât toate celelalte la un loc, deci nu poate fi anulat complet — supraviețuiește ca ultim candidat.
Pas cu pas
Pe v = {2, 2, 1, 2, 3, 2, 2}:
i=0: x=2 contor 0 -> candidat=2, contor=1
i=1: x=2 ==cand -> contor=2
i=2: x=1 !=cand -> contor=1
i=3: x=2 ==cand -> contor=2
i=4: x=3 !=cand -> contor=1
i=5: x=2 ==cand -> contor=2
i=6: x=2 ==cand -> contor=3Candidat final: 2. Starea contorului ca diagramă, urmărind „energia" candidatului:
1 | 2 | 1 | 2 | 1 | 2 | 3 |
A doua parcurgere: verificarea
Votul dă mereu un candidat, chiar dacă vectorul nu are majoritar. Confirmă numărând:
#include <iostream>
using namespace std;
int main() {
int v[7] = {2, 2, 1, 2, 3, 2, 2};
int n = 7;
// pasul 1: gaseste candidatul
int candidat = v[0], contor = 0;
for (int i = 0; i < n; i++) {
if (contor == 0) candidat = v[i];
if (v[i] == candidat) contor++;
else contor--;
}
// pasul 2: verifica majoritatea
int aparitii = 0;
for (int i = 0; i < n; i++) {
if (v[i] == candidat) aparitii++;
}
if (aparitii > n / 2) cout << candidat << "\n"; // 2
else cout << "Nu exista element majoritar\n";
return 0;
}Complexitate
| Metodă | Timp | Spațiu |
|---|---|---|
| vector de frecvență | O(n) | O(valoare maximă) |
| Boyer-Moore | O(n) | O(1) |
Capcane la elementul majoritar:
- Omiterea verificării finale: fără a doua parcurgere, returnezi un candidat fals când nu există majoritar.
- Confuzi „majoritar" cu „cel mai frecvent": cel mai frecvent element poate apărea de mai puțin de n/2 ori; majoritarul cere strict peste n/2.
- Compari
aparitii >= n/2: pentrunpar,n/2apariții nu sunt majoritate. Condiția corectă e> n/2. - Resetezi contorul greșit: candidatul se schimbă doar când contorul e exact 0, înainte de a procesa elementul curent.
Recapitulare
- Majoritarul apare strict de peste n/2 ori; dacă există, e unic.
- Boyer-Moore găsește candidatul în O(n) timp și O(1) memorie, prin anulări reciproce.
- E obligatorie o a doua parcurgere care confirmă că aparițiile candidatului depășesc n/2.