分治演算法求N個數中第K小(大)的數
阿新 • • 發佈:2019-01-28
這個學期開演算法課,跟著進度寫寫程式碼就好。這周講分治,說到了求N個數中第K小(大)數的問題,寫寫看。
分治演算法的複雜度是O(n),用到了快速排序的思路:先選取一個參考數進行一次快排,拿升序來說的話,快排之後左邊所有數<參考數,右邊所有數>參考數,然後根據左右部分各自包含元素的個數,計算要求的元素在哪個區間內(要求的元素或是左區間中的第k小數,或是右區間中第[k-j]小數,j為左區間的長度),然後遞迴求解。
本來pku 2104和pku 2761都是求第K小數的題,無奈用這個演算法TLE,只能用後面的劃分樹或是其他複雜度更低的演算法來做,以後再說吧。我這裡只貼用這個演算法做的,雖然交上去會TLE...
#include <iostream> using namespace std; int partition(int[], int, int); int Select(int[], int, int, int); int main() { int n, m; int l, r, k; int v[100002]; int d[100002]; cin >> n >> m; for (int i = 1; i <= n; i++) cin >> v[i]; while (m--) { cin >> l >> r >> k; for (int j = l; j <= r; j++) d[j] = v[j]; cout << Select(d, l, r, k) << endl; } return 0; } //一次快速排序 int partition(int s[], int l, int r) { if (l < r) { int i = l; int j = r; int x = s[i]; while (i < j) { while (i < j && s[j] >= x) j--; if (i < j) s[i++] = s[j]; while (i < j && s[i] < x) i++; if (i < j) s[j--] = s[i]; } s[i] = x; return i; } return -1; } //分治找K-th Number int Select(int s[], int l, int r, int k) { if (l > r) return -1; if (l == r) return s[l]; //得到中間數的下標 int i = partition(s, l, r); //j為左區間長度 int j = i - l + 1; //位置大就在左區間找,否則就在右區間找 if (j == k) return s[i]; else if (j > k) return Select(s, l, i, k); else return Select(s, i+1, r, k-j); }