열심히 코딩 하숭!

1655번 가운데를 말해요 | baekjoon 문제 풀이 본문

코딩테스트/baekjoon

1655번 가운데를 말해요 | baekjoon 문제 풀이

채숭이 2022. 9. 18. 22:56

https://www.acmicpc.net/problem/1655

 

1655번: 가운데를 말해요

첫째 줄에는 백준이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 백준이가 외치는 정수가 차례대로 주어진다. 정수는 -1

www.acmicpc.net

 

문제

백준이는 동생에게 "가운데를 말해요" 게임을 가르쳐주고 있다. 백준이가 정수를 하나씩 외칠때마다 동생은 지금까지 백준이가 말한 수 중에서 중간값을 말해야 한다. 만약, 그동안 백준이가 외친 수의 개수가 짝수개라면 중간에 있는 두 수 중에서 작은 수를 말해야 한다.

예를 들어 백준이가 동생에게 1, 5, 2, 10, -99, 7, 5를 순서대로 외쳤다고 하면, 동생은 1, 1, 2, 2, 2, 2, 5를 차례대로 말해야 한다. 백준이가 외치는 수가 주어졌을 때, 동생이 말해야 하는 수를 구하는 프로그램을 작성하시오.

입력

첫째 줄에는 백준이가 외치는 정수의 개수 N이 주어진다. N은 1보다 크거나 같고, 100,000보다 작거나 같은 자연수이다. 그 다음 N줄에 걸쳐서 백준이가 외치는 정수가 차례대로 주어진다. 정수는 -10,000보다 크거나 같고, 10,000보다 작거나 같다.

출력

한 줄에 하나씩 N줄에 걸쳐 백준이의 동생이 말해야 하는 수를 순서대로 출력한다.

 


 

시간초과가 난 문제다. 데이터를 삽입 후 삭제하는 부분에 시간이 많이 소요되어서 비효율적인 방법이었던 것 같다.

그래도 VS로 돌렸을 때 정답은 나왔으니... 일단 나의 풀이를 적고, 다시 풀어본 후 효율적인 정답을 찾게되면 이곳에 다시 공유하도록 하겠다.

 

 

문제 해설

우선순위 큐 하나와 스택 하나를 두었다. 그리고 주어지는 중간값을 우선순위 큐에 담았다. 이때, 담기면서 값들은 자동으로 maxheap정렬 된다.

 

그 후, mid(== (i + 1) / 2 + 1)라는 값을 설정하고 mid번 우선순위 큐에서 root값을 pop을 해준 후 그 중 제일 마지막으로 pop된 값이 중간값이므로 이를 출력해주었다. 그리고 mid번 pop할 때 pop된 값들을 스택에 저장했다.

 

마지막으로, 원래의 상태로 돌아가기 위해 스택에 저장되어 있는 값들을 다시 우선순위 큐에 넣어주었다.

 

풀이 코드

#include <iostream>
#include <queue> 
#include <stack>
using namespace std;

int main() {

	int N, num;
	cin >> N;
	priority_queue<int> numbers; // 우선순위큐 maxheap
	stack<int> st; // 중간에 값을 저장하고 가져오는 용도로 사용할 스택

	int n; // 중간값을 저장하기 위한 변수 n

	for (int i = 0; i < N; i++) {
		cin >> num;
		numbers.push(num);

		int mid = (i + 1) / 2 + 1; // mid - 1 만큼의 값을 heap에서 pop()해야 함

		for (int j = 0; j < mid; j++) {
			n = numbers.top();
			st.push(n); // 스택에 n을 push해 저장함.
						// 나중에 다시 우선순위 큐로 들어갈 때 정렬 되니까 순서는 상관 없으므로 스택에 담은 것임
			numbers.pop(); // 가장 우선순위가 높은(값이 큰) 값을 pop()
		}
		cout << n << '\n'; // 가장 최근에 pop된 값이 중간값이므로 이를 출력

		while (!st.empty()) { // 저장한 값들을 다시 우선순위 큐로 옮기기
			numbers.push(st.top());
			st.pop(); // 옮긴 후 pop()
		}
	}

	return 0;
}