最小的K个数_牛客题霸_牛客网
描述
给定一个长度为 n 的可能有重复值的数组,找出其中不去重的最小的 k 个数。例如数组元素是4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4(任意顺序皆可)。
数据范围:0≤k,n≤100000≤k,n≤10000,数组中每个数的大小0≤val≤10000≤val≤1000
要求:空间复杂度 O(n)O(n) ,时间复杂度 O(nlogk)O(nlogk)
示例1
输入:[4,5,1,6,2,7,3,8],4 返回值:[1,2,3,4]
说明:返回最小的4个数即可,返回[1,3,2,4]也可以
解法:
1.分治:快排思想,比较K和分治后pos的大小,如果相等,说明找到了,pos前面的数就是结果.,题目要求还需要对pos前的元素进行排序。
2.维护一个K个节点的大根堆,对于[k,n-1]之间的元素,每次拿堆顶元素和当前元素对比,交
换比堆顶元素小的,重新调整。
3.书中解题,多重哈希表,哈希表从大到小排序,依次往哈希表插入k个元素,如果哈希表有了k个元素,往后每遍历一个值,把0号元素(最大值)和当前元素进行对比,0号元素比进来的元素小,删除0号元素,插入当前元素。
1.分治
#include <any>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param input int整型vector
* @param k int整型
* @return int整型vector
*/
// 分治
int partition(vector<int>& input, int left, int right, int k ){
int i = left, j = left;
for(; i < right; ++i){
if(input[i] < input[right]){
swap(input[i], input[j]);
++j;
}
}
swap(input[j],input[right]);
if(j == k - 1) return j;
else if(j > k - 1) return partition(input, left, j-1, k);
else if(j < k - 1) return partition(input, j+1, right, k);
return -1;
}
vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
// write code here
if(!k || input.empty()) return vector<int>{};
vector<int> res;
// 1.分治
int res_pos = partition(input, 0, input.size() - 1, k);
copy_n(input.begin(), k,back_inserter(res));
return res;
}
};
2.K个节点的大根堆
#include <any>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param input int整型vector
* @param k int整型
* @return int整型vector
*/
vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
// write code here
if(!k || input.empty()) return vector<int>{};
vector<int> res;
// 2.K个结点的大根堆
int nums_size = input.size();
for(int idx = k / 2 - 1; idx >=0 ; --idx){
adjustMaxHeap(input, idx, k);
} //维护K个结点的大根堆
for(int idx = k; idx < nums_size; ++idx){
if(input[0] > input[idx]){ //把K后面的值依次和堆顶比较, 如果堆顶元素>新插入的元素
swap(input[0], input[idx]);
adjustMaxHeap(input, 0, k); //调整为大根堆
}
}
copy_n(input.begin(), k, back_inserter(res));
sort(res.begin(), res.end());
return res;
}
//维护一个k个结点的大根堆
void adjustMaxHeap(vector<int>&input, int pos, int len){
int dad = pos;
int son = 2*dad +1;
while(son < len){
if(son +1 < len && input[son] < input[son+1]){
++son;
}
if(input[son] > input[dad] ){
swap(input[son],input[dad]);
dad = son;
son = 2 * dad + 1;
}
else break;
}
}
};
3.multi_set
#include <any>
#include <functional>
#include <iterator>
#include <utility>
#include <vector>
class Solution {
public:
/**
* 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
*
*
* @param input int整型vector
* @param k int整型
* @return int整型vector
*/
vector<int> GetLeastNumbers_Solution(vector<int>& input, int k) {
// write code here
if(!k || input.empty()) return vector<int>{};
vector<int> res;
//书中解题3,多重哈希表,哈希表从大到小排序,依次往哈希表插入k个元素,
//如果哈希表有了k个元素,往后每遍历一个值,把0号元素和当前元素进行对比,0号元素比进来的元素小,删除0号元素,插入当前元素。
multiset<int, greater<int>> hash_table;
for(int idx = 0; idx < input.size(); ++idx){
if(hash_table.size() < k){
hash_table.insert(input[idx]);
}
else{
if(*hash_table.begin() > input[idx]){
hash_table.erase(hash_table.begin());
hash_table.insert(input[idx]);
}
}
}
// //从小到大插入结果容器vector
copy(hash_table.rbegin(),hash_table.rend(), back_inserter(res));
return res;
}
};