topK问题

使用堆排序来求解  数组维持k个数 新来的元素和根进行比较  找k个最大值 建小堆  此时堆顶为最小值 当新来的元素比堆顶元素还要小  直接抛弃就可以了  因为不可能是最大值  否则  堆顶为新来的元素  替换堆顶在进行重新调整  (找最小值同样原理) 调整的时候根据最后一个父节点开始调整  遵循从下到上 从右向左的原理 时间复杂度为:O(nlogk)  不会修改输入的数组

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//寻找最大的k个数  建立k个小顶堆 
void HeapAdjust(vector<int>&res,int pos)  //根
{
	for(int i=2*pos+1;i<res.size();i=2*i+1)
	{
		if((i<res.size()-1)&&(res[i]>res[i+1]))  //i<res.size()-1  防止越界
			i++;                                 //i一直++  左一直大于右  循环出来 
                                                 //不满足条件  将这个小的值和根比
		if(res[i]>res[pos]) break;               //此时根是最小的 不变
		swap(res[i],res[pos]);                   //否则孩子比根还小  交换孩子与根
		pos = i;
	}
}
void topK(vector<int>&vec,int k)
{
	if(vec.size()<k) return;
	vector<int>res;
	res.resize(k);  //设置数组中的个数为k
	for(int i=0;i<k;i++)
		res[i] = vec[i];
	for(int i=res.size()/2-1;i>=0;i--)
		HeapAdjust(res,i);
	for(int i=k;i<vec.size();i++)
	{
		if(vec[i]>res[0])
		{
			res[0] = vec[i];
			HeapAdjust(res,0);
		}
	}
	for(auto i:res)
		cout<<i<<" "<<endl; 

}

int main()
{
	vector<int>vec;
	vec.push_back(38);
	vec.push_back(25);
	vec.push_back(97);
	vec.push_back(1);
	vec.push_back(2);
	topK(vec,3);
	system("pause");
	return 0;
}

找k个最小值

#include<iostream>
#include<vector>
#include<algorithm>
using namespace std;

//找k个最小值  建大根堆  
void Adjust(vector<int>&res,int pos)  //根
{
	for(int i=2*pos+1;i<res.size();i++)
	{
		if((i<res.size()-1)&&(res[i]<res[i+1]))  //i<res.size()-1  防止越界
			i++;               //不满足i++说明左边比右边大
		if(res[pos]<res[i])   //res[pos]是根的值 建大根堆
		{
			swap(res[pos],res[i]);
		}
		else
			break;
		pos = i;
	}
}

void top_k(vector<int>&vec,int k)
{
	if(vec.size()<k) return;
	vector<int>res;  //设置最终的数组  元素容量为k
	res.resize(k);
	for(int i=0;i<k;i++)
		res[i] = vec[i];
	//调整堆顶  res[0] 为最大值
	for(int i=res.size()/2-1;i>=0;i--)
	{
		Adjust(res,i);    //最后一个根开始调整
	}
	for(int i=k;i<vec.size();i++)
	{
		if(vec[i]<res[0])
		{
			res[0] = vec[i];
			Adjust(res,0);
		}
	}
	for(auto i:res)
		cout<<i<<" "<<endl;
}
int main()
{
	vector<int>vec;
	vec.push_back(3);
	vec.push_back(38);
	vec.push_back(0);
	vec.push_back(9);
	vec.push_back(1);
	top_k(vec,4);
	system("pause");
	return 0;
}

或者使用优先队列

#include<iostream>
#include<vector>
#include<algorithm>
#include<queue>
#include<functional>  //greater的头文件
using namespace std;

//优先队列   底层是堆实现的  求前k个最大值  最大值 建小堆
vector<int>topk(vector<int>&vec,int k)
{
	priority_queue<int,vector<int>,greater<int>>heap;   //less大堆  greater小堆  优先队列默认是大堆
	for(int i=0;i<k;i++)
	{
		heap.push(vec[i]);
		if(heap.size()>k)
			heap.pop();
	}
	vector<int>res;
	while(heap.size())
	{
		res.push_back(heap.top());
		heap.pop();
	}
	return res;
}
int main()
{
	vector<int>res;
	vector<int>vec;
	vec.push_back(5);
	vec.push_back(9);
	vec.push_back(100);
	vec.push_back(1);
	vec.push_back(0);
	res = topk(vec,3);
	for(auto i:res)
		cout<<i<<endl;
	system("pause");
	return 0;
}

快排思想 :找一个标准值 将比标准值小的都放在左侧  比标准大的都放在右侧 

最小的k个数 :如果我们基于第k个数来调整 比第k个数小的都放在左侧  比第k个数大的都放在右侧  因为我们每次查找一次 都会选择出一个更小的值 所以最后遍历一遍数组  时间复杂度为O(n)  但是前提是我们对传入的数组进行了修改

#include<iostream>
#include<vector>
using namespace std;

//最小的k个数  基于快排的思想
int Search(vector<int>&vec,int nlow,int nhigh)
{
	if(vec.empty()||nlow>nhigh) return -1;
	int nsmall = nlow-1;
	for(nlow;nlow<nhigh;nlow++)
	{
		if(vec[nlow]<vec[nhigh])
		{
			if(++nsmall!=nlow)  //因为异或有个条件 是不可以操作同一块空间  
			{                   //其实是nsmall先加加  然后跟nlow进行比较
				vec[nsmall] = vec[nsmall]^vec[nlow];
				vec[nlow] = vec[nsmall]^vec[nlow];
				vec[nsmall] = vec[nsmall]^vec[nlow];
			}
		}
	}
	if(++nsmall!=nhigh)
	{
		vec[nsmall] = vec[nsmall]^vec[nhigh];
		vec[nhigh] = vec[nsmall]^vec[nhigh];
		vec[nsmall] = vec[nsmall]^vec[nhigh];
	}
	return nsmall;
}
vector<int>topk(vector<int>&vec,int k)
{
	vector<int>res;
	if(vec.size()<k) return res;
	int nlow = 0;
	int nhigh = vec.size()-1;
	int index = Search(vec,nlow,nhigh);
	while(index!=k-1)   //以第k个为基准
	{
		if(index>k-1)  //操作的都是下标  在第k个值后面了
		{
			nhigh = index-1; 
			index = Search(vec,nlow,nhigh);
		}
		else               //在第k个值前面
		{  
			nlow = index+1;
			index = Search(vec,nlow,nhigh);
		}
	}

	for(int i=0;i<k;i++)
		res.push_back(vec[i]);
	return res;
}
int main()
{
	vector<int>res;
	vector<int>vec;
	vec.push_back(3);
	vec.push_back(1);
	vec.push_back(2);
	vec.push_back(4);
	vec.push_back(5);
	res = topk(vec,2);
	for(auto i:res)
		cout<<i<<endl;
	system("pause");
	return 0;
}

 

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值