題目描述:
輸入n個整數,找出其中最小的K個數。例如輸入4,5,1,6,2,7,3,8這8個數字,則最小的4個數字是1,2,3,4。
解題思路:
方法一:
原理類似於博客數組中出現次數超過一半的數的方法一,參考鏈接:https://blog.csdn.net/Victory_tc/article/details/87566304
方法二:
利用大頂堆(multiset)來存儲最小的k個數;首先當大定堆中元素個數小於K時,將數組中的元素插入其中;然後當大定堆中有了k個以後,將數組中當前遍歷元素與之比較,小於堆頂元素,則堆頂元素不可能是最小的k個數之一,所以將其刪除後,插入當前的數組元素;以此遍歷完數組,大頂推中便是最小的k個數。
方法總結:
1)方法一時間複雜度O(n),但是要變動原數組元素的位置;方法二時間複雜度爲O(nlogk)(大頂堆的插入,刪除時間複雜度都爲O(logk)),適用於處理海量數據(n非常大,以至於不能一次性載入內存中,k較小)。
2)方法一不適合海量數據,變動了原數組,但是時間複雜度較低;方法二適用於海量數據,沒有變動原數組。
通過代碼(C++):
方法一:
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> result;
if(input.empty() || k > input.size() || k <= 0)
return result;
int middle = k-1;
int start = 0;
int end = input.size() - 1;
int index = partion(input,start,end);
while(index != middle)
{
if(index > middle)
{
end = index - 1;
}
else
{
start = index + 1;
}
index = partion(input,start,end);
}
//判斷輸入是否存在超過數組長度一半的數
result.assign(input.begin(),input.begin()+k);
return result;
}
//快速排序的基礎,返回選中的基準值在數組中的位置
int partion(vector<int>&numbers, int start, int end)
{
int len = numbers.size();
if(numbers.empty() || start < 0 || end >= len)
return -1;
//產生start-end的隨機數
int index = RandomInRange(start,end);
swap(numbers[index],numbers[end]);
int small = start - 1;
for(index = start; index < end; ++index)
{
if(numbers[index] < numbers[end])
{
++small;
if(small != index)
swap(numbers[small],numbers[index]);
}
}
++small;
swap(numbers[small],numbers[end]);
return small;
}
//產生[start,end]的隨機數
int RandomInRange(int start,int end)
{
std::mt19937 rng;//隨機數類型
rng.seed(std::random_device()());//初始化隨機數種子
//創建一個均勻分佈,這個均勻分佈可以等概率(隨機)生成[start,end]區間的整形數字;
std::uniform_int_distribution<int> dist(start,end);
return dist(rng);
}
};
方法二:
#include<set>
class Solution {
public:
vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
vector<int> result;
if(input.empty() || k > input.size() || k <= 0)
return result;
std::multiset<int,greater<int>> auxiliarySet;
std::vector<int>::const_iterator iter = input.begin();
for(; iter != input.end(); ++iter)
{
if(auxiliarySet.size() < k)
{
auxiliarySet.insert(*iter);
}
else
{
if(*iter < *(auxiliarySet.begin()))
{
std::multiset<int,greater<int>>::iterator iterSet = auxiliarySet.begin();
auxiliarySet.erase(iterSet);
auxiliarySet.insert(*iter);
}
}
}
std::multiset<int,greater<int>>::iterator iterSet = auxiliarySet.begin();
for(;iterSet != auxiliarySet.end(); ++iterSet)
{
result.push_back(*iterSet);
}
return result;
}
};