最小的k個數

轉載點擊打開鏈接

題目描述

輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4,。

解法一:排序

相信很多人會首先想到這種方法,先把數組按升序/降序進行排序,然後輸出 K 個最小/最大的數。

  • 常規的排序方法時間複雜度至少是Θ(nlog2n)Θ(nlog2n)。(快排或堆排序
  • 可能你會說,我們可以使用線性時間的排序算法。當然可以,但通常它們對輸入的數組有一定的要求。比如計數排序要求 n 個數都是正整數,且它們的取值範圍不太大。

解法二:部分排序 O(nk)O(n∗k)

由於我們只需要找出最小/最大的 k 個數,所以我們可以進行部分排序,比如簡單選擇排序 和 冒泡排序,它們每一趟都能把一個最小/最大元素放在最終位置上,所以進行 k 趟就能把 n 個數中的前 k 個排序出來。

部分簡單選擇排序:
void select_sort(int A[], int n, int k)
{
    for(int i=0; i<k; ++i) { // k趟
        int Min = i;         // 記錄最小元素的位置

        for(int j=i+1; j<n; ++j)
            if(A[j] < A[Min])
                Min = j;

        if(Min != i)  // 與A[i]交換
        {
            int tmp = A[Min];
            A[Min] = A[i];
            A[i] = tmp;
        }
    }
}
部分冒泡排序:
void bubble_sort(int A[], int n, int k)
{
    for(int i=0; i<k; ++i)  // k趟
    {
        bool flag = false;
        for(int j=n-1; j>i; --j)  // 一趟冒泡過程
            if(A[j-1] > A[j])
            {
                int tmp = A[j-1];
                A[j-1] = A[j];
                A[j] = tmp;
                flag = true;
            }
        if(flag == false)  // 已經有序
            return ;
    }
}

解法三:快排劃分 O(nlog2k)O(n∗log2k)

當我們求出第 k 順序統計量時,位於它前面的元素都比它小,位於它後面的元素都比它大。這時,數組的前 k 個數就是最小的 k 個數。

int partition(int A[], int low, int high)
{
    int pivot = A[low];
    while(low < high)
    {
        while(low < high && A[high]>=pivot)
            --high;
        A[low] = A[high];
        while(low < high && A[low]<=pivot)
            ++low;
        A[high] = A[low];
    }
    A[low] = pivot;
    return low;
}


int topK(int A[], int low, int high, int k)
{
    if(k <= 0)
        return -1;
    if(low == high)
        return low;

    int pos = partition(A, low, high);
    int i = pos - low + 1;
    if(i == k)
        return pos;  // 返回前k個數的
    else if(i > k)
        return topK(A, low, pos, k);
    else
        return topK(A, pos+1, high, k-i);
}



發佈了53 篇原創文章 · 獲贊 152 · 訪問量 13萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章