題目:輸入n個整數,輸出其中最小的k個。
例如輸入1,2,3,4,5,6,7和8這8個數字,則最小的4個數字為1,2,3和4。
分析:這道題最簡單的思路莫過於把輸入的n個整數排序,這樣排在最前面的k個數就是最小的k個數。只是這種思路的時間複雜度為O(nlogn)。我們試著尋找更快的解決思路。
我們可以開闢一個長度為k的數組。每次從輸入的n個整數中讀入一個數。如果數組中已經插入的元素少於k個,則將讀入的整數直接放到數組中。否則長度為k的數組已經滿了,不能再往數組裡插入元素,只能替換了。如果讀入的這個整數比數組中已有k個整數的最大值要小,則用讀入的這個整數替換這個最大值;如果讀入的整數比數組中已有k個整數的最大值還要大,則讀入的這個整數不可能是最小的k個整數之一,拋棄這個整數。這種思路相當於只要排序k個整數,因此時間複雜可以降到O(n+nlogk)。通常情況下k要遠小於n,所以這種辦法要優於前面的思路。
這是我能夠想出來的最快的解決方案。不過從給面試官留下更好印象的角度出發,我們可以進一步把代碼寫得更漂亮一些。從上面的分析,當長度為k的數組已經滿了之後,如果需要替換,每次替換的都是數組中的最大值。在常用的資料結構中,能夠在O(1)時間裡得到最大值的資料結構為最大堆。因此我們可以用堆(heap)來代替數組。
另外,自己重頭開始寫一個最大堆需要一定量的代碼。我們現在不需要重新去發明車輪,因為前人早就發明出來了。同樣,STL中的set和multiset為我們做了很好的堆的實現,我們可以拿過來用。既偷了懶,又給面試官留下熟悉STL的好印象,何樂而不為之?
參考代碼:
[cpp]
view plaincopy
- #include <set>
- #include <vector>
- #include <iostream>
-
- using namespace std;
-
- typedef multiset<int, greater<int> > IntHeap;
-
- ///////////////////////////////////////////////////////////////////////
- // find k least numbers in a vector
- ///////////////////////////////////////////////////////////////////////
- void FindKLeastNumbers
- (
- const vector<int>& data, // a vector of data
- IntHeap& leastNumbers, // k least numbers, output
- unsigned int k
- )
- {
- leastNumbers.clear();
-
- if(k == 0 || data.size() < k)
- return;
-
- vector<int>::const_iterator iter = data.begin();
- for(; iter != data.end(); ++ iter)
- {
- // if less than k numbers was inserted into leastNumbers
- if((leastNumbers.size()) < k)
- leastNumbers.insert(*iter);
-
- // leastNumbers contains k numbers and it's full now
- else
- {
- // first number in leastNumbers is the greatest one
- IntHeap::iterator iterFirst = leastNumbers.begin();
-
- // if is less than the previous greatest number
- if(*iter < *(leastNumbers.begin()))
- {
- // replace the previous greatest number
- leastNumbers.erase(iterFirst);
- leastNumbers.insert(*iter);
- }
- }
- }
- }
//補充的代碼
[cpp]
view plaincopy
- /*
- 解題報告:
- 1、最簡單的辦法,給所有資料按升序或降序排序,從中取出相應的k個就可以了,最快的時間複雜度為nlog(n)
- 2、可以考慮維護一個堆,這個堆的中元素的個數為k,然後遍曆元素,這時有兩種情況:
- 1、堆中元素的個數小於k,這時直接插入即可
- 2、元素的個數為k,這時如果遍曆到的元素小於堆中最大的那個元素就將堆中的這個元素刪除,將遍曆到的元素插入即可
- */
-
- #include <iostream>
- #include <set>
- #include <vector>
- using namespace std;
-
- typedef multiset<int, greater<int> > intHeap;
-
- void FindNumbers(vector<int> &data, int k, intHeap &numbers)
- {
- numbers.clear();
- if (0==k || data.size()<k)
- return ;
- vector<int>::const_iterator iter = data.begin();
- for (; iter!=data.end(); iter++)
- {
- if (numbers.size() < k)
- {
- numbers.insert(*iter);
- }
- else
- {
- intHeap::iterator heapIter = numbers.begin();
- if (*iter < *(numbers.begin()))
- {
- numbers.erase(heapIter);
- numbers.insert(*iter);
- }
- }
- }
- }
-
- int main()
- {
- int n;
- vector<int> data;
- intHeap numbers;
- while (cin>>n)
- {
- for (int i=0; i<n; ++i)
- {
- int nTemp;
- cin>>nTemp;
- data.push_back(nTemp);
- }
- FindNumbers(data, 4, numbers);
- intHeap::const_iterator iter = numbers.begin();
- for (; iter!=numbers.end(); ++iter)
- {
- cout<<*iter<<" ";
- }
- cout<<endl;
- }
- return 0;
- }
//我的借鑒方法
[cpp]
view plaincopy
- #include <iostream>
- #include <algorithm>
- #include <vector>
- #include <cmath>
- #include <set>
-
- using namespace std;
-
- //print an array of int
- inline void print(int *arr, //the array of int
- int n //the length of array
- )
- {
- for(int i=0;i<n;i++)
- cout<<arr[i]<<"\t";
- cout<<endl;
-
- }
- typedef multiset<int, greater<int> > IntHeap;
-
-
- ///////////////////////////////////////////////////////////////////////
- // find k least numbers in a vector
- ///////////////////////////////////////////////////////////////////////
- void FindKLeastNumbers(
- // vector<int>& data, // a vector of data
- int *array,
- unsigned int len,
- IntHeap& leastNumbers, // k least numbers, output
- unsigned int k )
- {
-
- std::vector <int> data(array, array + len);
-
- leastNumbers.clear();
-
- if(k == 0 || data.size() < k)
- return;
-
- vector<int>::const_iterator iter = data.begin();
- for(; iter != data.end(); ++ iter)
- {
- // if less than k numbers was inserted into leastNumbers
- if((leastNumbers.size()) < k)
- leastNumbers.insert(*iter);
-
- // leastNumbers contains k numbers and it's full now
- else
- {
- // first number in leastNumbers is the greatest one
- IntHeap::iterator iterFirst = leastNumbers.begin();
-
- // if is less than the previous greatest number
- if(*iter < *(leastNumbers.begin()))
- {
- // replace the previous greatest number
- leastNumbers.erase(iterFirst);
- leastNumbers.insert(*iter);
- }
- }
- }
- }
-
-
- void main()
- {
- int arr[ 10 ] = {3, 4, 8, 6, 0, 1, 5, 7, 2, 9};
-
- int len = sizeof(arr) / sizeof(int);
-
- int LeastNumers = 5;
-
- IntHeap numbers;
-
- FindKLeastNumbers(arr,len,numbers,LeastNumers);
-
- IntHeap::const_iterator iter = numbers.begin();
- for (; iter != numbers.end(); ++iter)
- {
- cout<<*iter<<" ";
- }
- cout<<endl;
- }