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 |