Broj različitih
Dato je n celih brojeva (do 109 po apsolutnoj vrednosti, n ≤ 2·105). Ispiši koliko je među njima različitih.
Primer
Ulaz
6
5 -2 5 1000000000 -2 7Izlaz
4Kontejneri set i map čuvaju elemente uređene i omogućavaju dodavanje, brisanje i traženje u vremenu O(log n). Na takmičenjima služe za brojanje pojavljivanja, uklanjanje duplikata, praćenje najmanjeg i najvećeg elementa i traženje najbližeg elementa dok se skup menja.
set čuva svaki element najviše jednom, uvek sortirano. Dodavanje postojećeg elementa ne menja ništa.
#include <iostream>
#include <set>
using namespace std;
int main() {
set<int> s;
s.insert(5);
s.insert(1);
s.insert(9);
s.insert(5); // 5 već postoji – ništa se ne menja
cout << "veličina: " << s.size() << endl;
for (int x : s) cout << x << " "; // uvek rastuće
cout << endl;
cout << "ima li 9? " << s.count(9) << endl; // 1 ili 0
s.erase(9);
cout << "ima li 9? " << s.count(9) << endl;
cout << "najmanji: " << *s.begin() << endl;
cout << "najveći: " << *s.rbegin() << endl;
return 0;
}
| Operacija | Značenje | Složenost |
|---|---|---|
s.insert(x) | dodaje x | O(log n) |
s.erase(x) | briše x | O(log n) |
s.count(x) | 1 ako x postoji, inače 0 | O(log n) |
*s.begin(), *s.rbegin() | najmanji i najveći element | O(1) |
s.lower_bound(x) | iterator na prvi element >= x | O(log n) |
s.size(), s.empty() | broj elemenata, da li je prazan | O(1) |
Sortiran niz i lower_bound rade dok se niz ne menja. Ako se elementi dodaju između upita, koristimo metodu s.lower_bound(x) skupa. Primer: parking mesta se zauzimaju jedno po jedno, a za svako novo vozilo tražimo prvo slobodno mesto sa brojem >= x.
#include <iostream>
#include <set>
using namespace std;
int main() {
int n, q;
cin >> n >> q; // mesta 1..n, q vozila
set<int> slobodna;
for (int i = 1; i <= n; i++) slobodna.insert(i);
while (q--) {
int x;
cin >> x; // vozač želi mesto x ili prvo veće
auto it = slobodna.lower_bound(x);
if (it == slobodna.end()) {
cout << "nema" << endl;
} else {
cout << *it << endl;
slobodna.erase(it); // mesto je sada zauzeto
}
}
return 0;
}
multiset dozvoljava više jednakih elemenata, a i dalje je sortiran. Pažnja: ms.erase(x) briše sve kopije broja x; jednu kopiju brišemo preko iteratora: ms.erase(ms.find(x)).
#include <iostream>
#include <set>
using namespace std;
int main() {
multiset<int> ms = {4, 1, 4, 7, 4};
cout << "četvorki: " << ms.count(4) << endl;
ms.erase(ms.find(4)); // briše samo jednu četvorku
cout << "četvorki: " << ms.count(4) << endl;
for (int x : ms) cout << x << " ";
cout << endl;
return 0;
}
Multiset je zgodan kada treba stalno znati najmanji i najveći od trenutnih elemenata, a elementi se i dodaju i brišu (na primer, cene u prodavnici koje se menjaju).
map<K, V> svakom ključu pridružuje vrednost. Osnove su opisane u lekciji Rečnik podataka – mape u C++; ovde je najvažnija primena – brojanje pojavljivanja kada su vrednosti prevelike za običan niz brojača (do 109, negativne, ili reči).
#include <iostream>
#include <map>
#include <string>
using namespace std;
int main() {
int n;
cin >> n;
map<string, int> br; // reč -> broj pojavljivanja
for (int i = 0; i < n; i++) {
string rec;
cin >> rec;
br[rec]++; // nova reč automatski dobija 0, pa se uveća
}
for (auto &par : br) // ključevi su sortirani abecedno
cout << par.first << " " << par.second << endl;
return 0;
}
br[x] za ključ koji ne postoji dodaje ga sa vrednošću 0. Za proveru postojanja koristi br.count(x).Verzije bez uređenja koriste heš tabelu: dodavanje i traženje su u proseku O(1), ali elementi nisu sortirani i nema lower_bound. Koriste se kada redosled nije bitan, a operacija ima mnogo.
| set / map | unordered_set / unordered_map | vector + sort | |
|---|---|---|---|
| Traženje | O(log n) | O(1) prosečno | O(log n) (binarna pretraga) |
| Dodavanje u toku rada | O(log n) | O(1) prosečno | sporo (O(n)) |
| Sortiran redosled | da | ne | da |
| Najbliži element | da (lower_bound) | ne | da |
| Kada | dinamički skup, uređenost | samo brojanje / postojanje | podaci se ne menjaju |
Za svaki zadatak postoji primer, uputstvo i rešenje. Rešenja su provereno tačna na primerima iz teksta.
Dato je n celih brojeva (do 109 po apsolutnoj vrednosti, n ≤ 2·105). Ispiši koliko je među njima različitih.
6
5 -2 5 1000000000 -2 74Dato je n reči. Ispiši reč koja se javlja najviše puta i broj njenih pojavljivanja; ako ih ima više, ispiši abecedno prvu.
7
mama ima mama tata ima mama bakamama 34
b a b aa 2U prodavnici se događaju promene. Upit + x dodaje proizvod cene x, upit - x uklanja jedan proizvod cene x (sigurno postoji), a upit ? traži da se ispišu najmanja i najveća trenutna cena (ili prazno).
7
+ 5
+ 3
+ 5
?
- 3
- 5
?3 5
5 5set ne čuva duplikate; ako su potrebni, koristi multiset.ms.erase(x) briše sve kopije, ms.erase(ms.find(x)) samo jednu.lower_bound(s.begin(), s.end(), x) nad skupom – to je O(n). Ispravno je s.lower_bound(x).*it) proveri da nije end().1. Koliko elemenata ima set posle insert(3), insert(3), insert(5)?
2. Koja je složenost dodavanja u set?
3. Šta se desi kada se pročita br["x"] za ključ koji ne postoji u mapi br?
4. Kako se iz multiseta uklanja samo jedna kopija broja x?