나는 당신의 힙 아이디어를 좋아합니다. 나는 실제로 그것이 당신이 열거 한 시간 범위 내에서 작동 할 것이라고 생각하고 분석에 약간의 결함이 있다고 생각합니다.
다음을 수행한다고 가정 해보십시오. 배열에서 내부 힙을 빌드 한 다음 최소 k 개 요소를 큐에서 빼내고 나머지 n-k 요소는 배열의 어느 위치에 두었습니다. 요소가 어디에서 끝날지 생각하면 배열의 k 번째 요소가 배열의 뒤에 오름차순으로 저장되어야하고 나머지 n-k 요소는 힙 순서로 앞에 있어야합니다. 이것을 보는데 어려움이 있다면, heapsort가 어떻게 작동하는지 생각해보십시오 - k가 대기열에서 제외 된 후에 가장 큰 k 요소가 뒤에 내림차순으로 있고 나머지 요소는 앞에 힙순으로 정렬되어 있습니다. 여기서는 max-heap을위한 min-heap을 교환했기 때문에 이상한 순서가 있습니다. 결과적으로 끝에서 배열을 뒤집을 경우 앞에 k 값이 작은 요소가 앞에오고 n-k 나머지 요소가옵니다. 다음
이 올바르게 K 작은 요소를 찾을 것이며, 실행은 판정 :
heapify의
- 비용 : O (n)은 K를 꺼내의
- 비용 : O (K 로그 N) 어레이를 반전
- 비용 : O (N)
- 총 비용 : O (N + K 로그 N) 지금
, 가정 K ≤ N 그/로그 n. 그런 다음 런타임은
O (N + K 로그 n을) = O는 (N + (N/로그 n)이 로그 n) = O는 (n)이
그래서이 완료입니다! 알고리즘은 잘 작동합니다. 또한, O (1) 보조 공간이 필요합니다 (힙을 내장 할 수 있으며 O (1) 공간에서 배열을 뒤집을 수 있습니다).
더 잘 할 수 있습니다. @timrau는 quickselect (또는 더 일반적으로 선형 시간 선택 알고리즘)를 사용한다는 주석에서 제안했습니다. 이 알고리즘은 배열의 첫 번째 k 슬롯에 순서대로 최하위 k 개의 요소를 넣고 마지막 n - k 슬롯에 남아있는 n - k 요소를 순서대로 배열하도록 배열을 다시 배열합니다. 그렇게하면 k (nifty!)에 관계없이 O (n) 시간이 걸립니다. 여러분이 그렇게했다고 가정하고, 첫 번째 k 요소를 정렬하면됩니다.이것은 O (n + k log n) 시간 힙 기반 알고리즘보다 점근 적으로 나은 시간 O (n + k log k)를 필요로합니다.
알려진 선형 시간 선택 알고리즘 중에서 조심하면 빠른 선택과 중앙값 알고리즘을 모두 구현할 수 있으므로이 방법에 필요한 총 공간은 O (1)입니다.
[Quickselect] (http://en.wikipedia.org/wiki/Quickselect) 알고리즘. – timrau
C++ ['std :: partial_sort()'] (http://en.cppreference.com/w/cpp/algorithm/partial_sort) – timrau
@timrau가 있습니다. O (n) algo를 사용하여 약 k 번째 칸을 분할 한 다음 첫 번째 k를 정렬하십시오. 이것은 O (n + k log k)와 일정한 공간입니다. – Gene