給定 n (≤ 2,000,000) 個整數,求第 k 小的數。多測試用例,輸入規模大,需快速 IO 和 O(n) 算法。
| 算法 | 平均時間 | 最壞時間 | 空間 | 備註 |
|---|---|---|---|---|
| 快速選擇 | O(n) | O(n²) | O(1) | 隨機化 pivot 避免最壞 |
| BFPRT (中位數的中位數) | O(n) | O(n) | O(1) | 理論最優,常數大 |
| nth_element (STL) | O(n) | O(n log n) | O(log n) | 工程首選,Introselect 混合策略 |
| 計數排序 | O(n+R) | O(n+R) | O(R) | 數值範圍 R 小時極快 |
#include
#include
#include
using namespace std;
const int MAXN = 2000005;
int a[MAXN];
// 快速輸入
inline bool readInt(int& x) {
int c = getchar();
if (c == EOF) return false;
while (c <= ' ') c = getchar();
bool neg = false;
if (c == '-') { neg = true; c = getchar(); }
x = 0;
while (c >= '0') { x = x * 10 + c - '0'; c = getchar(); }
if (neg) x = -x;
return true;
}
int main() {
int n, k;
while (readInt(n) && readInt(k)) {
for (int i = 0; i < n; ++i) readInt(a[i]);
nth_element(a, a + k - 1, a + n);
printf("%d\n", a[k-1]);
}
return 0;
}
int quickSelect(int* a, int l, int r, int k) { // 0-based, 求第 k 小 (k 從 0 開始)
while (l < r) {
int pivot = a[l + rand() % (r - l + 1)];
int i = l, j = r;
while (i <= j) {
while (a[i] < pivot) ++i;
while (a[j] > pivot) --j;
if (i <= j) swap(a[i++], a[j--]);
}
if (k <= j) r = j;
else if (k >= i) l = i;
else return a[k];
}
return a[l];
}
inline int fastRead() {
int c, x = 0;
do c = getchar(); while (c <= ' ');
bool neg = false;
if (c == '-') { neg = true; c = getchar(); }
for (; c >= '0'; c = getchar()) x = (x << 3) + (x << 1) + (c - '0'); // x*10
return neg ? -x : x;
}
`(x<<3)+(x<<1)` 等價 `x*10`,無乘法指令,極快。