https://www.acmicpc.net/problem/24060
코드설명
정렬(Sort) + 분할정복(DivideAndConquer) 을 활용합니다.
K번쨰 저장되는 숫자를 구하기 위해서는 단순히 병합정렬을 구현한뒤 병합정렬에 값이 저장되는 순간을 한개씩 증가시키면서 K번째일떄 해당 답을 저장하면 됩니다.
코드
먼저, 병합정렬을 구현해보았습니다.
병합정렬은 여러가지 방식으로 구현가능한데요, 일단은 int[] 를 반환하여서 직접 배열을 반환하는 방식으로 구현했습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.StringTokenizer;
public class Main {
private static int C, N, M, W, H, K;
private static int answer = 0;
private static int[] arr;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
// StringTokenizer st = new StringTokenizer(br.readLine());
arr = mergeSort(new int[] {1, 111, 111, 121, 5, 99, 2, 4, 6, 100}, 0, 7);
for(int v : arr ) {
System.out.println(v);
}
}
//mergeSort는 병합하면서 정렬하는 방식이다.
//즉, 먼저 분할을 해줘야한다는 것 이다.
private static int[] mergeSort(int[] A, int left, int right) {
//만약 사이즈가 같아진다면, 1개만 남았으므로 반환한다.
if(left >= right) {
return new int[] {A[left]};
}
// 0 1 2 3 4 5 6 7
// mid는 7/2 = 3.5. 3이라 생각.
//
// 0 1 2 3 4 5 6
// mid는 6/2 = 3. 3 이라 생각.
//먼저, 2개로 나누는 과정이다.
int mid = (left + right) / 2;
int[] leftArr = mergeSort(A, left, mid);
int[] rightArr = mergeSort(A, mid + 1, right);
return merge(leftArr, rightArr);
}
//
private static int[] merge(int[] left, int[] right) {
int[] mergedArr = new int[left.length + right.length];
int mergedIdx = 0;
int leftIdx = 0, rightIdx = 0;
while(leftIdx < left.length && rightIdx < right.length) {
// while(leftIdx < left.length && rightIdx < right.length && left[leftIdx] < right[rightIdx]) {
// mergedArr[mergedIdx++] = left[leftIdx];
// leftIdx++;
// }
// while(leftIdx < left.length && rightIdx < right.length && right[rightIdx] < left[leftIdx]) {
// mergedArr[mergedIdx++] = right[rightIdx];
// rightIdx++;
// }
if(left[leftIdx] <= right[rightIdx]) {
mergedArr[mergedIdx++] = left[leftIdx++];
}
else if(left[leftIdx] > right[rightIdx]) {
mergedArr[mergedIdx++] = right[rightIdx++];
}
}
//아직 다 못한것들.
while(leftIdx < left.length) {
mergedArr[mergedIdx++] = left[leftIdx];
leftIdx++;
}
while(rightIdx < right.length) {
mergedArr[mergedIdx++] = right[rightIdx];
rightIdx++;
}
return mergedArr;
}
}
정답코드1 입니다
package Main;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.StringTokenizer;
public class Main {
private static int C, N, M, W, H, K;
private static int answer = 0;
private static int[] arr;
private static int mergedCnt = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
arr = new int[N];
st = new StringTokenizer(br.readLine());
for(int i=0;i<N;i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
mergeSort(arr, 0, arr.length - 1);
if(mergedCnt < K) System.out.println(-1);
else System.out.println(answer);
}
//mergeSort는 병합하면서 정렬하는 방식이다.
//즉, 먼저 분할을 해줘야한다는 것 이다.
private static int[] mergeSort(int[] A, int left, int right) {
//만약 사이즈가 같아진다면, 1개만 남았으므로 반환한다.
if(left >= right) {
return new int[] {A[left]};
}
// 0 1 2 3 4 5 6 7
// mid는 7/2 = 3.5. 3이라 생각.
//
// 0 1 2 3 4 5 6
// mid는 6/2 = 3. 3 이라 생각.
//먼저, 2개로 나누는 과정이다.
int mid = (left + right) / 2;
int[] leftArr = mergeSort(A, left, mid);
int[] rightArr = mergeSort(A, mid + 1, right);
return merge(leftArr, rightArr);
}
//
private static int[] merge(int[] left, int[] right) {
int[] mergedArr = new int[left.length + right.length];
int mergedIdx = 0;
int leftIdx = 0, rightIdx = 0;
while(leftIdx < left.length && rightIdx < right.length) {
// while(leftIdx < left.length && rightIdx < right.length && left[leftIdx] < right[rightIdx]) {
// mergedArr[mergedIdx++] = left[leftIdx];
// leftIdx++;
// }
// while(leftIdx < left.length && rightIdx < right.length && right[rightIdx] < left[leftIdx]) {
// mergedArr[mergedIdx++] = right[rightIdx];
// rightIdx++;
// }
if(left[leftIdx] <= right[rightIdx]) {
if(++mergedCnt == K) {
answer = left[leftIdx];
}
mergedArr[mergedIdx++] = left[leftIdx++];
}
else if(left[leftIdx] > right[rightIdx]) {
if(++mergedCnt == K) {
answer = right[rightIdx];
}
mergedArr[mergedIdx++] = right[rightIdx++];
}
}
//아직 다 못한것들.
while(leftIdx < left.length) {
if(++mergedCnt == K) {
answer = left[leftIdx];
}
mergedArr[mergedIdx++] = left[leftIdx];
leftIdx++;
}
while(rightIdx < right.length) {
if(++mergedCnt == K) {
answer = right[rightIdx];
}
mergedArr[mergedIdx++] = right[rightIdx];
rightIdx++;
}
return mergedArr;
}
}
두번쨰 정답코드입니다.
문제의 의사코드를 참고하여 구현했습니다. 사실, 이 코드가 merge 부분에서만 [] 을 생성하여 처리하므로 더 빠를 줄 알았는데, 실제로 비교해보면 시간은 거의 똑같습니다.
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;
public class Main {
private static int C, N, M, W, H, K;
private static int answer = 0;
private static int[] arr;
private static int mergedCnt = 0;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
N = Integer.parseInt(st.nextToken());
K = Integer.parseInt(st.nextToken());
arr = new int[N];
st = new StringTokenizer(br.readLine());
for(int i=0;i<N;i++) {
arr[i] = Integer.parseInt(st.nextToken());
}
mergeSort(arr, 0, arr.length - 1);
//System.out.println(mergedCnt);
if(mergedCnt < K) System.out.println(-1);
else System.out.println(answer);
}
private static void mergeSort(int[] A, int lo, int hi) {
if(lo == hi) {
return ;
}
//분할한다.
int mid = (lo + hi)/2;
mergeSort(A, lo, mid);
mergeSort(A, mid + 1, hi);
//합친다.
merge(A, lo, mid, hi);
return ;
}
private static void merge(int[] A, int lo, int mid, int hi) {
int[] temp = new int[hi - lo + 1];
int tempIdx = 0;
int left = lo;
int right = mid + 1;
while(left <= mid && right <= hi) {
if(A[left] < A[right]) {
if(++mergedCnt == K) {
answer = A[left];
}
temp[tempIdx++] = A[left++];
}else {
if(++mergedCnt == K) {
answer = A[right];
}
temp[tempIdx++] = A[right++];
}
}
while(left <= mid) {
if(++mergedCnt == K) {
answer = A[left];
}
temp[tempIdx++] = A[left++];
}
while(right <= hi) {
if(++mergedCnt == K) {
answer = A[right];
}
temp[tempIdx++] = A[right++];
}
for(int i=lo; i<=hi; i++) {
A[i] = temp[i - lo];
}
}
}
'알고리즘 > 백준' 카테고리의 다른 글
[백준] 6986 절사평균 - 정렬(Sort) JAVA (0) | 2024.08.14 |
---|---|
[백준] 25418 정수 a를 k로 만들기 - 동적계획법(Dynamic Programming, DP) JAVA (0) | 2024.08.12 |
[백준] 20310 타노스 - 그리디(탐욕법, Greedy) JAVA (0) | 2024.08.07 |
[백준] 17484 진우의 달 여행 (Small) - 동적계획법(Dynamic Programming) + 비트마스킹(BitMask) JAVA (0) | 2024.08.05 |
[백준] 17175 피보나치는 지겨웡~ - 동적계획법(DP, Dynamic Programming) JAVA (0) | 2024.08.04 |