Quick Selection은 퀵 정렬과 유사하지만, 분할 후 가 포함된 구역만 재귀적으로 탐색하여 평균 시간 복잡도 을 보장합니다.
데이터가 많을 때 피벗을 단순히 맨 앞이나 뒤로 잡으면 최악의 경우 에 빠질 수 있습니다. 이를 방지하기 위해 배열의 중간값을 피벗으로 설정하는 로직을 추가했습니다.
int m = (s + e) >>> 1; // 중간 인덱스 계산
swap(arr, s, m); // 중간값을 맨 앞으로 보내 피벗으로 사용
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
StringTokenizer st = new StringTokenizer(br.readLine());
int n = Integer.parseInt(st.nextToken());
int k = Integer.parseInt(st.nextToken());
int[] a = new int[n];
st = new StringTokenizer(br.readLine());
for (int i = 0; i < n; i++) {
a[i] = Integer.parseInt(st.nextToken());
}
quickSelect(a, 0, n - 1, k);
System.out.println(a[k - 1]);
}
private static void quickSelect(int[] arr, int s, int e, int k) {
if (s >= e) return;
int pivot = partition(arr, s, e);
if (pivot == k - 1) return;
else if (pivot > k - 1) quickSelect(arr, s, pivot - 1, k);
else quickSelect(arr, pivot + 1, e, k);
}
private static int partition(int[] arr, int s, int e) {
// 중간값 피벗 설정으로 최악의 케이스 방지
int m = (s + e) >>> 1;
swap(arr, s, m);
int pivot = arr[s];
int i = s + 1, j = e;
while (i <= j) {
while (i <= j && arr[j] > pivot) j--;
while (i <= j && arr[i] < pivot) i++;
if (i <= j) swap(arr, i++, j--);
}
swap(arr, s, j);
return j;
}
private static void swap(int[] arr, int i, int j) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}