【hihoCoder】#1133 : 二分·二分查找之k小數
阿新 • • 發佈:2019-03-06
txt hihocoder 主元 優先 right 表示 堆排 print \n
題目描述
在上一回裏我們知道Nettle在玩《艦これ》,Nettle的鎮守府有很多船位,但船位再多也是有限的。Nettle通過撈船又出了一艘稀有的船,但是已有的N(1≤N≤1,000,000)個船位都已經有船了。所以Nettle不得不把其中一艘船拆掉來讓位給新的船。Nettle思考了很久,決定隨機選擇一個k,然後拆掉稀有度第k小的船。 已知每一艘船都有自己的稀有度,Nettle現在把所有船的稀有度值告訴你,希望你能幫他找出目標船。
輸入
第1行:2個整數N,k。N表示數組長度,
第2行:N個整數,表示a[1..N],保證不會出現重復的數,1≤a[i]≤2,000,000,000。
輸出
第1行:一個整數t,表示t在數組中是第k小的數,若K不在數組中,輸出-1。
樣例輸入
10 4
1732 4176 2602 6176 1303 6207 3125 1 1011 6600
樣例輸出
1732
算法
無意間刷到這題,並且原題已經給出算法的提示。趁著這題讓我回顧了下快速排序,並且在這邊先記錄這題算法的核心思想。
快速排序每次都能確定一個元素的位置,也就是說,能知道這個元素是數組中第幾小的數。那麽將k與該元素所在的位置進行比較: 如果正好就是第k小的數,直接打印退出即可; 如果該位置比k大,說明第k小的數在該元素左邊的那堆數中,往左邊走,重復之前的步驟; 如果該位置比k小,說明第k小的數在該元素右邊的那堆數中,往右邊走,重復之前的步驟。 由於不是進行全局的交換位置,每次都交換需要尋找的區域,所以時間復雜度為O(logn);但是當遇見一開始就完全有序的情況,或者是從大到小排序的情況就比較蛋疼,所以最後能放置一個標誌位,如果一輪下來不曾交換可以直接通過數學的方法計算出第k小的位置。當然,這是在本題中這麽說,如果真實的快排中,選擇主元是一門比較大的學問。 當然這題也可以用堆排序實現,維護一個N-k這麽大的最小堆,最後的堆頂就是需要找的元素,說實話借助優先隊列的話,還是十分簡單的。
代碼
#include <iostream> using namespace std; void Swap(int &a, int &b) { int tmp = a; a = b; b = tmp; } int main() { // freopen("stdin.txt", "r", stdin); int N, k; scanf("%d %d", &N, &k); int Arr[N]; for (int i = 0; i < N; i++) { scanf("%d", &Arr[i]); } if (k < 1 || k > N) printf("-1\n"); // 算法主體 int left = 0, right = N-1; while(left <= right) { int pivot = Arr[left]; int p = left, q = right; while (1) { while (Arr[q] >= pivot && q > p) q--; while (Arr[p] <= pivot && p < q) p++; if (p < q) swap(Arr[p], Arr[q]); else break; } Swap(Arr[left], Arr[p]); // for (int f = 0; f < N; f++) // cout << Arr[f] << ' '; // cout << endl; if(p == k-1) { printf("%d\n", Arr[p]); break; } else if (p > k-1) right = p - 1; else left = p + 1; } return 0; }
【hihoCoder】#1133 : 二分·二分查找之k小數