문제 해석
- 문제는 제목 그대로 병합 정렬을 하여 오름차순으로 정렬하는 것이다.
- 그렇다면, 병합 정렬(= 합병 정렬, merge sort)은 무엇일까?
- 분할(Divide) : 입력 배열을 같은 크기의 2개의 부분 배열로 분할한다.
- 정복(Conquer) : 부분 배열을 정렬한다. 부분 배열의 크기가 충분히 작지 않으면 순환 호출 을 이용하여 다시 분할 정복 방법을 적용한다.
- 결합(Combine) : 정렬된 부분 배열들을 하나의 배열에 합병한다
출처 : https://gmlwjd9405.github.io/2018/05/08/algorithm-merge-sort.html
- 다시 문제로 넘어오면, 첫번째 줄에서 배열의 크기(N)과 저장 횟수(K)를 입력받는다.
- 입력받았다면 N개만큼 배열의 원소를 입력받는다.
코드
import java.io.*;
import java.util.Arrays;
import java.util.StringTokenizer;
public class Main {
int[] A;
static int[] tmp;
static int result = -1;
static int cnt = 0;
static int K;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int N = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
int[] A = new int[N];
tmp = new int[N];
st = new StringTokenizer(br.readLine());
for(int i = 0; i < N; i++){
A[i] = Integer.parseInt(st.nextToken());
}
merge_sort(A, 0, N-1);
System.out.println(result);
}
static void merge_sort(int A[], int p, int r){
if(cnt > K) return;
if(p < r){
int q = (p+r)/2;
merge_sort(A, p, q);
merge_sort(A,q+1, r);
merge(A, p, q, r);
}
}
static void merge(int Array[], int p, int q, int r){
int i = p;
int j = q + 1;
int t = 0;
while(i <= q && j <= r){
if(Array[i] < Array[j]){
tmp[t++] = Array[i++];
}
else{
tmp[t++] = Array[j++];
}
}
while(i <= q){
tmp[t++] = Array[i++];
}
while(j <= r){
tmp[t++] = Array[j++];
}
i = p;
t = 0;
while(i <= r){
cnt++;
if(cnt == K){
result = tmp[t];
break;
}
Array[i++] = tmp[t++];
}
}
}
/*
예를 들어, 입력 값이 아래의 정수이라고 가정할 때,
5 7
4 5 1 3 2
*/
Array 배열 (2) : 4 5 1 3 2
tmp 배열 (2): 4 5 0 0 0
Array 배열 (2) : 4 5 1 3 2
tmp 배열 (2): 4 5 0 0 0
Array 배열 (2) : 1 5 1 3 2
tmp 배열 (2): 1 4 5 0 0
Array 배열 (2) : 1 4 1 3 2
tmp 배열 (2): 1 4 5 0 0
Array 배열 (2) : 1 4 5 3 2
tmp 배열 (2): 1 4 5 0 0
Array 배열 (2) : 1 4 5 2 2
tmp 배열 (2): 2 3 5 0 0
Array 배열 : 1 4 5 2 2 -> 정렬을 하다가 cnt = K를 만나 종료되는 것을 알 수 있다. (즉, 정렬이 되다 끝남...)
tmp 배열 : 2 3 5 0 0
- 이 아래부터는 재귀함수를 썼기 때문에 merge_sort에서 if(cnt > K) return 안걸린 부분을 수행하는 것을 알 수 있다.
Array 배열 (2) : 1 4 5 2 2
tmp 배열 (2): 1 2 2 4 5
Array 배열 (2) : 1 2 5 2 2
tmp 배열 (2): 1 2 2 4 5
Array 배열 (2) : 1 2 2 2 2
tmp 배열 (2): 1 2 2 4 5
Array 배열 (2) : 1 2 2 4 2
tmp 배열 (2): 1 2 2 4 5
Array 배열 (2) : 1 2 2 4 5
tmp 배열 (2): 1 2 2 4 5
- merge_sort에서 if(cnt > K) return에 걸려 분리와 정렬은 완전히 끝이 난다.
결과
느낀 점
- 의사코드를 보고 코드로 그대로 옮기면 금방 풀 수 있었겠지만 그냥 가져다 쓰기보단 로직을 이해하고 싶었다...
- 그 덕분에 이 로직을 이해하는데 3일 연속으로 보고 또 봤고... 생각보다 너무 오래걸렸다. (머리가 많이 굳었긴 했나보다... 꾸준히 해야하는데😩)