- 문제
백준이는 동생에게 "가운데를 말해요" 게임을 가르쳐주고 있다. 백준이가 정수를 하나씩 외칠때마다 동생은 지금까지 백준이가 말한 수 중에서 중간값을 말해야 한다. 만약, 그동안 백준이가 외친 수의 개수가 짝수개라면 중간에 있는 두 수 중에서 작은 수를 말해야 한다.
예를 들어 백준이가 동생에게 1, 5, 2, 10, -99, 7, 5를 순서대로 외쳤다고 하면, 동생은 1, 1, 2, 2, 2, 2, 5를 차례대로 말해야 한다. 백준이가 외치는 수가 주어졌을 때, 동생이 말해야 하는 수를 구하는 프로그램을 작성하시오.
//시간 제한: 0.1초 , 메모리 제한: 128MB
- 입력
첫째 줄에는 백준이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 백준이가 외치는 정수가 차례대로 주어진다. 정수는 -10,000보다 크거나 같고, 10,000보다 작거나 같다.
- 출력
한 줄에 하나씩 N줄에 걸쳐 백준이의 동생이 말해야 하는 수를 순서대로 출력한다.
// Created by dongwan-kim on 2022/07/27.
#include<iostream>
#include<queue>
using namespace std;
priority_queue<int> Max;
priority_queue<int, vector<int>, greater<>> Min;
int n, num;
int main() {
ios::sync_with_stdio(false);
cin.tie(0);
cin >> n;
for (int i = 0; i < n; i++) {
cin >> num;
if (Max.size() > Min.size())
Min.push(num);
else
Max.push(num);
if (Min.empty()) {
cout << Max.top() << "\n";
continue;
}
if (Max.top() > Min.top()) {
Min.push(Max.top());
Max.push(Min.top());
Max.pop();
Min.pop();
}
cout << Max.top() << "\n";
}
}
priority queue를 이용하여 문제를 해결했다.
내림차순 Max pq 와 오름차순 Min pq를 생성해서
Max의 top이 항상 중앙값이 되도록 구현했다.
Max와 Min은 사이즈가 같거나 Max의 사이즈가 하나 크도록 항상 유지했다.
숫자를 입력받은 시점에서 지금까지 받은 값이 홀수개라면 Max의 size가 하나 크고 짝수개라면 Max와 Min의 사이즈가 같게 된다.
로직은 간단하다. Max에는 Min보다 작은값을 Min에는 Max보다 큰 값을들 넣으면 Max의 top이 중앙값이 될 수 밖에 없다. 만약 입력하는 과정에서 Max의 top이 Min의 top보다 커지면 두개를 스왑해 주었다.
이 문제는 구현은 굉장히 빨리 했지만 알고리즘을 떠올리는게 굉장히 오랜 시간이 걸렸다.
시간 제한에 맞춰 문제 해결할 방법이 잘 떠오르지 않아서 확실한 것부터 정하고 고민하자는 생각으로 우선, 인덱스를 사용하거나 반복문을 통해 비교해서 출력하는 것은 불가능 하다는 것을 먼저 깨달았고, 값을 넣었을 때 정렬해주는 자료구조가 필요하다고 생각하여 pq를 선택하게 되었다. 그랬더니 조금 더 고민하니 위와 같은 방법이 떠올랐다.