著者: Zhai Tianbao Steven
著作権表示: 著作権は著者に属します。商業的転載の場合は、許可について著者に連絡してください。非商業的な転載の場合は、出典を示してください。
タイトル説明:
重複値を含む可能性のある長さ n の配列を指定して、重複を削除しない最小の k 数値を見つけます。たとえば、配列要素は 8 つの数値 4、5、1、6、2、7、3、8 であり、最小の 4 つの数値は 1、2、3、4 (順序は任意) です。
データ範囲: 0≤k、n≤10000、配列内の各数値のサイズは 0≤val≤1000
要件: 空間計算量 O(n)、時間計算量 O(nlogk)
例:
入力:
[4,5,1,6,2,7,3,8],4
戻り値:
[1,2,3,4]
例証します:
最小の 4 つの数値を返すだけで十分ですが、[1,3,2,4] を返すこともできます。
問題解決のアイデア:
この質問は並べ替えの質問です。問題を解決する 2 つの方法。
1) クイックソート
クイックソート後、最初の k 値が取得され、時間計算量は O(nlogn)、空間計算量は O(k)、時間計算量はトピックの要件 O(nlogk) を満たしていません。このトピックはクイックソートに関するものではありません。
2) 優先キューに基づくヒープソート
優先キューを使用すると、ベクトルの走査の複雑さは n であり、毎回挿入されます。挿入はヒープ ソート (二分法) に基づいており、キュー内のデータは k に保たれているため、挿入の複雑さは logk です。合計時間計算量は O (nlogk) です。スペースに関しては、入力をクリアしてスペースを節約でき、一時スペースは必要なく、スペースの複雑さは O(1) です。
テストコード:
1) クイックソート
class Solution {
public:
// 获取最小K数
vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
int size = int(input.size());
// 快排
sort(input.begin(), input.end());
// 取k和size更小值,放置越界
int r = min(k, size);
// 获取结果
vector<int> result;
for(int i = 0; i < r; ++i){
result.push_back(input[i]);
}
return result;
}
};
2) 優先キューに基づくヒープソート
#include <queue>
class Solution {
public:
// 获取最小K数
vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
int size = int(input.size());
// 创建优先队列,默认采用less模式,即最大值作为优先级最高的值优先被推出,更小值保留在队列中
priority_queue<int> q;
// 遍历vector
for(int i = 0; i < size; ++i){
// 往优先队列中存数据时,已经进行了堆排序,插入的复杂度为logk
q.push(input[i]);
// 保持队列中只有k个数据,可以使插入的效率提高
if(q.size() > k){
// 最大值被推出
q.pop();
}
}
// 清空vector,节省空间
input.clear();
// 将优先队列中的数据放入vector
while(!q.empty()){
input.push_back(q.top());
q.pop();
}
return input;
}
};