BOJ 백준 16455 : K번째 수 찾는 함수
Updated:
시작하면서
이번 문제는 Medians and Order Statistics 문제이다. Introduction To Algorithms 책으로 개념 공부를 했고, 해당 문제를 이 문제에 적용해보고자 한다. (개념 공부 링크)
개념
개념에 대해 정리한 링크로 대체한다.
중앙값과 순서 통계량(Medians and Order Statistics)
문제 이해
문제를 읽어보자. 먼저 이 문제에서 나오는 변수는 총 3가지이다.
-
N : 배열의 크기
-
K : 찾아야 하는 수의 기준
-
시간 제한 : 0.1초
이 문제에서 중요한 점은 “시간 제한”이다. 최대 5,000,000 크기의 배열이므로 일반적인 정렬 알고리즘을 사용해서 O(nlogn)의 복잡도로 문제를 해결하면 예상되는 시간은 다음과 같다.
- 기준 : 1초당 1억개의 연산을 한다고 가정
- log(5000000) = 6.6989700043360188047862611052755
이렇게 기준을 잡았을 때 O(nlogn) = O(500000 * 6.6989…) = 33,494,850.0216800940239… = 약 0.3초가 되므로 시간 제한을 초과하게 된다고 예상할 수 있다.
공부한 Quick Selection은 시간 복잡도가 O(n)이므로 O(5000000) = 약 0.05초가 되므로 시간 제한에 걸리지 않는다고 예상할 수 있다.
문제 아이디어
개념 공부했던 내용을 바탕으로 알고리즘을 구현해서 진행하려고 한다. (개념 공부 링크 참조)
해결
#include <iostream>
#include <vector>
void swap(int* a, int* b);
int RandomizedSelect(std::vector<int>& v, int p, int r, int i);
int RandomizedPartition(std::vector<int>& v, int p, int r);
int Partition(std::vector<int>& v, int p, int r);
int kth(std::vector<int>& a, int k)
{
int ans = 0;
ans = RandomizedSelect(a, 0, a.size() - 1, k);
return ans;
}
void swap(int* a, int* b)
{
int c = *a;
*a = *b;
*b = c;
}
int RandomizedSelect(std::vector<int>& v, int p, int r, int i)
{
if (p == r)
{
return v[p];
}
int q = RandomizedPartition(v, p, r);
int k = q - p + 1;
if (i == k)
{
return v[q];
}
else if (i < k)
{
return RandomizedSelect(v, p, q - 1, i);
}
else
{
return RandomizedSelect(v, q + 1, r, i - k);
}
}
int RandomizedPartition(std::vector<int>& v, int p, int r)
{
int i = rand() % (r - p + 1) + p;
swap(&v[r], &v[i]);
return Partition(v, p, r);
}
int Partition(std::vector<int>& v, int p, int r)
{
int x = v[r];
int i = p - 1;
for (int j = p; j < r; j++)
{
if (v[j] <= x)
{
i = i + 1;
swap(&v[i], &v[j]);
}
}
swap(&v[i + 1], &v[r]);
return i + 1;
}
마치며
원래는 K번째 수 문제를 풀려고 했었다. 하지만 해당 문제는 정렬을 여러번 진행해야해서 개념의 취지와 맞지 않았다.
Quick Selection은 N이 굉장히 크고, 접근하려는 빈도가 낮을 때 사용하는 것이 좋아보인다. (정렬되지 않은 배열에서 K번째 크거나 작은 수 찾기)
Leave a comment