[백준] 1655번: 가운데를 말해요
[백준] 1655번: 가운데를 말해요
📌 문제
https://www.acmicpc.net/problem/1655
📌 설명
수들을 순차적으로 받으면서 각 반복마다 수열의 중앙값을 출력하는 문제이다. 처음에 생각한 방법은 우선순위 큐나 set 자료구조를 통해 최대/최소값을 빠르게 찾은 다음, 선형적으로 탐색하여 중앙값을 찾는 방법이었다. 결과적으로 이 방법은 TLE이다. 현재 원소의 수를 $k$라고 하면, 원소를 삽입하는 데 $O(log(k))$, 중앙값을 찾는 데 $O(k)$의 시간복잡도를 가진다. 이를 $N$번 반복하므로 전체 시간복잡도는 $O(N^2)$이다.
이 문제를 해결하는 핵심 아이디어는 두 개의 우선순위 큐를 사용하는 것이다. 중앙값보다 작은 값들을 저장하는 내림차순 기반 우선순위 큐 left, 중앙값보다 큰 값들을 저장하는 오름차순 기반 우선순위 큐 right를 사용한다. left 또는 right의 크기가 지나지게 커지는 경우에 대한 처리 방법을 추가로 생각해야 한다. 결과적으로 이 방법은 $O(N log(N))$의 시간복잡도를 가져 제한 시간 내 문제를 해결할 수 있다.
📌 코드
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <iostream>
#include <queue>
using namespace std;
int main() {
cin.tie(0);
ios::sync_with_stdio(0);
int n;
cin >> n;
priority_queue<int> left; // 중앙값을 기준으로 왼쪽에 위치한 수
priority_queue<int, vector<int>, greater<int>> right; // 중앙값을 기준으로 오른쪽에 위치한 수
for (int i = 0; i < n; i++) {
int x;
cin >> x;
// right에서 중앙값에 가까운 수(right.top())이 x보다 작으면 단순히 right에 x 삽입
if (!right.empty() && right.top() < x)
right.push(x);
else
left.push(x);
int mid = i / 2 + 1;
// left에 수가 치우친 경우
if (left.size() > mid) {
right.push(left.top());
left.pop();
}
else if (left.size() < mid) {
left.push(right.top());
right.pop();
}
cout << left.top() << "\n";
}
}
This post is licensed under CC BY 4.0 by the author.