1. 문제 정보
- 문제 번호: 10816번
- 문제 이름: 숫자 카드 2
- 문제 요약:
- 숫자 카드 N개를 가지고 있다. 정수 M개가 주어졌을 때, 이 수가 적힌 숫자 카드를 각각 몇 개 가지고 있는지 구하는 프로그램을 작성하라.
2. 접근 방법 (알고리즘)
❌ 첫 번째 시도: Vector + find_if (시간 초과)
처음에는 vector<pair<int, int>>를 만들어 {숫자, 개수}를 저장하고, 새로운 카드가 들어올 때마다 find_if로 기존에 있는 카드인지 확인했다.
- 원인: find_if는 선형 탐색(O(N)이다.
- 시간 복잡도: 카드를 입력받을 때마다 전체 벡터를 뒤지므로 O(N^2), 탐색 시에도 O(M X N)이 걸린다. N과 M이 각각 50만인 이 문제에서 이 방식은 반드시 시간 초과가 발생한다.
✅ 최종 접근: unordered_map 사용 (성공)
map을 쓰면 인덱스로 바로 접근이 가능하다!
데이터의 개수를 세거나 특정 키(Key)로 값을 즉시 찾아야 할 때는 해시 테이블(Hash Table) 기반의 unordered_map이 최적이다.
- 성능: 평균적으로 삽입과 탐색에 O(1)이 걸린다.
- 전체 복잡도: O(N + M)으로, 100만 건의 데이터도 매우 빠르게 처리할 수 있다.
3. 코드 구현 (정답)
#include <iostream>
#include <unordered_map> // 해시 테이블 기반 맵
using namespace std;
int main() {
// 입출력 최적화
ios::sync_with_stdio(false);
cin.tie(nullptr);
int n, m;
cin >> n;
// key: 카드 숫자, value: 개수
unordered_map<int, int> myCards;
// 1. 카드 입력 및 카운팅
for (int i = 0; i < n; i++) {
int num;
cin >> num;
// operator[]를 통해 key가 없으면 0으로 초기화 후 1 증가
myCards[num]++;
}
cin >> m;
// 2. 쿼리 수행
for (int i = 0; i < m; i++) {
int num;
cin >> num;
// key가 없으면 자동으로 0을 반환함
cout << myCards[num] << " ";
}
return 0;
}
4. 배운 점 & 회고 (TIL) ✍️
이번 문제를 풀면서 map 계열 컨테이너의 operator[]가 단순한 접근 이상의 기능을 수행한다는 점을 깊이 이해하게 되었다.
① map / unordered_map의 operator[] 동작 방식
C++의 맵 자료구조에서 myCards[num]과 같이 대괄호 연산자를 사용하면 내부적으로 다음과 같은 로직이 실행된다.
- Key가 존재하는 경우: 해당 Key에 연결된 Value의 참조를 반환한다.
- Key가 존재하지 않는 경우: * 새로운 원소를 맵에 자동으로 추가한다.
- Value 타입을 "기본 초기화(Default Initialization)" 하여 반환한다.
② "기본 초기화"의 마법
Value 타입이 int일 경우, 없는 Key를 호출하면 자동으로 int()가 호출되어 0이 들어간다.
- int, double 등 숫자 타입: 0 또는 0.0으로 초기화
- string 타입: "" (빈 문자열)로 초기화
- 사용자 정의 클래스: 기본 생성자 호출
이 덕분에 if (find...) 처럼 복잡한 존재 여부 확인 로직 없이 myCards[num]++ 한 줄로 카운팅을 끝낼 수 있다. 존재하지 않던 숫자가 들어오면 0이 생기자마자 ++되어 1이 되기 때문이다.
③ 주의할 점
이 기능은 편리하지만, 조회만 하려고 했는데 데이터가 삽입될 수 있다는 부작용이 있다.
단순히 특정 Key가 있는지만 확인하고 싶다면 operator[] 대신 find() 함수나 count() 함수를 써야 맵의 크기가 불필요하게 커지는 것을 막을 수 있다. vector나 set 같은 다른 컨테이너는 이런 자동 삽입 기능이 없으므로 오직 맵(Map) 계열만의 특징임을 기억해야 한다.
| 자료구조 | operator[] 특징 |
| vector | 인덱스 범위 초과 시 에러(Undefined Behavior) 발생 |
| map | 없는 Key 접근 시 기본값으로 원소 생성 후 반환 |
| unordered_map | map과 동일 (해시 기반이라 더 빠름) |
최적화된 자료구조와 언어의 특성을 잘 활용하면 코드가 훨씬 간결해지고 성능도 챙길 수 있다는 것을 다시금 느꼈다.
'알고리즘 문제풀이 > C++' 카테고리의 다른 글
| [백준/C++] 11723번: 집합 - 비트마스킹을 활용한 최적화 (0) | 2026.02.22 |
|---|---|
| [백준/C++] 1764번: 듣보잡 - set_intersection과 inserter 활용하기 (0) | 2026.02.22 |
| [백준/C++] 2164번: 카드2 - Vector의 함정과 Queue의 효율성 (0) | 2026.02.12 |
| [백준/C++] 1920번: 수 찾기 - 시간 초과를 피하는 자료구조와 입출력 최적화 (0) | 2026.02.12 |
| [백준/C++] 10814번: 나이순 정렬 - Stable Sort (0) | 2026.02.09 |