1. 程式人生 > >【hihoCoder】#1133 : 二分·二分查找之k小數

【hihoCoder】#1133 : 二分·二分查找之k小數

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小數