面試題30 尋找最大(小)的k個數

2021-06-24 18:19:45 字數 2766 閱讀 6731

題目描述:輸入n個整數,輸出其中最大的k個。

舉例:輸入序列1、2、3、4、5、6、7、8,輸出最大的4個數字為5、6、7、8。

可能存在的條件限制:

要求 時間 和 空間消耗最小、海量資料、待排序的資料可能是浮點數等

思路:使用最快排序演算法,選擇快排 或 堆排

時間複雜度:o(n*logn) + o(k) = o(n*logn)

特點:需要對全部元素進行排序,k = 1 時,時間複雜度也為o(n*logn)

注意:題中只需得到最大的k個數,而不需要對後面n-k個數排序

思路:使用 選擇排序 或 起泡排序,進行k次選擇,可得到第k大的數

時間複雜度:o(n*k)

思路:尋找第k個大元素。

解法一:o(n)的演算法,需要修改陣列值(需要交換數值),尋找最大的k個數

具體方法:使用類似快速排序,執行一次快速排序後,每次只選擇一部分繼續執行快速排序,直到找到第k個大元素為止,此時這個元素在陣列位置後面的元素即所求。

在陣列s中找出乙個元素x,把陣列分為兩部分sa和sb。sa中的元素大於等於x,sb中元素小於x。

這時有兩種情況:

1. sa中元素的個數小於k,則sb中的第k-|sa|個元素即為第k大數;

2. sa中元素的個數大於等於k,則返回sa中的第k大數。

時間複雜度:因為每次只選擇一部分遞迴,所以時間複雜度為n(1+1/2+1/4+....+1/x)<2n,所以複雜度為o(n).

若隨機選取樞紐,線性期望時間o(n)。

若選取陣列的「中位數」作為樞紐,最壞情況下的時間複雜度o(n)

以下**用的是中位數法,得到最大的k個數。

下面的方法是找到最小的k個元素。如果想要找最大的k個元素,實際要找的是最小的size-k個元素。

樞紐元就選擇第乙個元素。

void swap(vector& input, int i, int j) 

int partition(vector& input, int start, int end) else

} swap(input, high, start);

return high;

}void recursion(vector& input, int start, int end, int k)

int mid = partition(input, start, end);

if (k == mid+1) else if (k > mid+1) else

}vectorgetleastnumbers_solution(vectorinput, int k)

recursion(input, 0, size-1, k);

ret.assign(input.begin(), input.begin() + k);

return ret;

}

如果是求最小的k個數,可以有下面的解法二。

解法二:o(nlogk)演算法,無需修改原有陣列,特別適合處理海量資料

我們可以建立乙個大小為k的容器來儲存最小k的數字,接下來遍歷陣列,每次讀入乙個數。

如果容器中的數字個數少於k,則直接把這個數插入到容器中;

如果容器中已有k個數,此時我們不能再插入新的數字,而只是替換已有的數字。

當容器滿了後,我們要做3件事:

1. 在已有的k個數中找到最大值;

2. 有可能在容器中刪除最大值

3. 有可能要插入這個新的數。

如果我們用二叉樹實現這個資料容器,那麼我們可以在o(logk)時間內實現這三個步驟。

因此,對於n個數字而言,複雜度為o(nlogk)。

紅黑樹的查詢、插入、刪除時間複雜度都是o(logn),所以我們可以用紅黑樹實現這個容器。

stl中的set和multiset都是基於紅黑樹實現的,元素都是有序的。

因此我們可以用multiset(可以存放重複元素)實現這個容器。

具體**如下:

type multiset> intset //比較方法是greater,所以set中的元素按從大到小排列

type multiset>::iterator intsetiterator

intset getleastknumbers(vector&data, int k)

for(vector::iterator it = data.begin(); it != data.end(); ++it)

else

}} return ret;

}

兩種解法的比較:第一種解法,基於分割槽,即類似快速排序的方法,雖然時間複雜度是o(n),但是需要修改陣列的值。

第二種解法雖然慢一點,但是有兩個優點,一是無需修改原陣列的值,二是適合海量資料處理。

我們每次讀入data中的乙個元素,讀寫都只是在大小為k的容器中進行的,如果是海量的資料,我們就不能把所有資料一次性裝入記憶體,第一種方法就不行了。

而第二種方法判斷是否需要把新資料放入到容器中,只要要求記憶體大小能夠容納這個容器即可,因此最適合的情形就是n很大,k很小的情況。

下表總結了這兩種解法的特點:

面試題30 最小的k個數

題目 輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4.思路1,同29題一樣,利用快排思想,醉倒第k大的數,它左邊都比它小即可。o n 2,適合海量資料,利用堆資料結果,取數o 1 刪除和插入需要o k 總共n個數,時間複雜度o ...

面試題30 最小的k個數

輸入n個整數,找出其中最小的k個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4。思路1 按遞增排序,然後輸出前k個數,簡單粗暴,時間複雜度o nlogn 思路2 利用partition演算法,找到第k大數,輸出其左邊k個數,時間複雜度o n 思路3 開乙個規模...

面試題30 最小的k個數

1.輸入n個整數,找出其中的最小的k個數,例如輸入4,5,1,6,2,7,3,8 這8個數字,則其中最小的4個數字是1,2,3,4,分析 方法一,可以採用類似快速排序的解法,基於陣列中第k個數來進行調整,使得比第k個數字大的所有數字都在陣列的右邊,小的都在第k個數字的左邊。方法二 可以建立乙個大小為...