Uknow's Lab.
article thumbnail

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

 

2696번: 중앙값 구하기

첫째 줄에 테스트 케이스의 개수 T(1 ≤ T ≤ 1,000)가 주어진다. 각 테스트 케이스의 첫째 줄에는 수열의 크기 M(1 ≤ M ≤ 9999, M은 홀수)이 주어지고, 그 다음 줄부터 이 수열의 원소가 차례대로 주

www.acmicpc.net

난이도 : 골드 2
태그 : 자료구조, 우선순위 큐

 

 

1. 설명

수를 차례로 입력받아가면서,

홀수 번째 수를 입력받았을 때 중앙값을 출력하는 문제입니다.

 

음.. 매번 정렬을 하면 당연히 시간초과가 날 것 같고,

정렬을 하는게 목적이 아니라, 단순히 중앙값을 찾는게 목적이기 때문에

우선순위 큐를 두 개 사용하면 해결할 수 있을 것 같습니다.

 

저는 일단, 절반을 기준으로 작은 값을 담는 lowQ, 큰 값을 담는 highQ 두 개를 만들어봤습니다.

lowQ는 내림차순, highQ는 오름차순 정렬로 지정하고,

 

이 두개는 지금까지 입력받은 숫자가 짝수개일 때는 크기가 같아야 하고,

홀수일 경우에는 lowQ가 highQ 보다 1 만큼 사이즈가 더 크도록 만든 뒤,

홀수개일 때 마다 lowQ의 맨 윗 숫자를 출력해주는 방식으로 작동합니다.

 

1 5 6 9 2 이 차례로 들어온다고 해봅시다.

 

1회차) 입력받은 수 - 1 , 남은 수 - 5 6 9 2

lowQ - 1

highQ - (빔)

첫 번째 수의 경우, lowQ에 일단 넣습니다. 또한, 지금까지 입력받은 숫자가 홀수개이므로 lowQ의 맨 위에 있는 1을 출력합니다.

 

2회차) 입력받은 수 2, 남은 수 - 6 9 2

lowQ의 맨 윗 값인 1 보다 2가 크므로 highQ에 넣습니다.

lowQ - 1

highQ - 2

 

3회차) 입력받은 수 6, 남은 수 - 9 2

입력받은 수 6이 lowQ의 맨 윗값인 1보다 크므로 highQ에 넣습니다.

lowQ - 1, highQ - 2, 6

하지만, 입력받은 수가 홀수개일 때, lowQ가 1만큼 더 크도록 해주도록 해야 하므로,

highQ에서 맨 위에 있는 수를 꺼내 lowQ에 넣습니다.

lowQ - 1, 2 highQ - 6

또, lowQ의 맨 위에 있는 값 (2)를 꺼냅니다. lowQ는 내림차순 입니다.

 

 

4회차) 입력받은 수 9, 남은 수 - 2

lowQ의 맨 위에 있는 수 2 보다 입력받은 수 9가 크므로 highQ에 쏙 넣어줍시다.

lowQ - 1, 2   highQ - 6, 9

 

5회차) 입력받은 수 11, 남은수 - x

lowQ의 맨 위에 있는 수 2 보다 입력받은 수 11이 크므로 highQ에 넣습니다.

lowQ - 1, 2, highQ - 6, 9, 11

다만, 이번에서 lowQ가 highQ 보다 1 만큼 그게 해 줄 것이므로, highQ 하나를 꺼내 lowQ에 하나 넣습니다.

lowQ - 1, 2, 6 highQ - 9, 11

또, 홀수번째 숫자이므로, lowQ 맨 위에 있는 숫자를 출력합니다.

 

위와 같은 방식으로, 매 번 중앙값을 찾을 수 있습니다.

 

 

 

2. 소스코드

<kotlin />
import java.lang.StringBuilder import java.util.Collections import java.util.PriorityQueue fun main() = with(System.`in`.bufferedReader()) { val sb = StringBuilder() repeat(readLine().toInt()) { val n = readLine().toInt() sb.append((n + 1) / 2).append("\n") val lowQ = PriorityQueue<Int>(Collections.reverseOrder()) val highQ = PriorityQueue<Int>() var cnt = 1 // 10개씩 띄워서 주므로 repeat(n / 10 + 1) { row -> val nums = readLine().split(" ").map { it.toInt() } for (col in nums.indices) { // 10개 마다 한 줄 띄워서 출력 // cnt는 매번 +1 해주고, 중앙값은 홀수일 때만 출력하므로 cnt%20 == 0 if (cnt % 20 == 0) { sb.append("\n") } // lowQ의 맨 윗값 보다 크다면 highQ에 offer if (lowQ.isNotEmpty() && nums[col] > lowQ.peek()) { highQ.offer(nums[col]) } else { // lowQ의 맨 윗값 보다 작다면 lowQ에 offer lowQ.offer(nums[col]) } // 두 개 큐 개수 맞춰주기 while (lowQ.size < highQ.size) { lowQ.offer(highQ.poll()) } while (lowQ.size - 1 > highQ.size) { highQ.offer(lowQ.poll()) } // 홀수개일 경우 출력 if (cnt++ % 2 == 1) { sb.append(lowQ.peek()).append(" ") } } } sb.append("\n") } print(sb) }

 

 

 

 

3. 후기

비슷한 문제를 한 번 풀어봤기에, 그리 어렵지 않게 풀 수 있었습니다.

우선순위 큐를 이렇게 쓴다고? 하면서 풀었던 기억이 나네요 ㅎㅎ...

profile

Uknow's Lab.

@유노 Uknow

인생은 Byte와 Double 사이 Char다. 아무말이나 해봤습니다.