【剑指offer】29.最小的K个数

题目

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。


分析

本题最简答的思路就是利用快速排序对数组进行排序,然后将遍历数组将最小的K个数输出即可。但是这样时间复杂度将会是 O ( n l o g n ) O(nlogn) O(nlogn),这样不够高效。解决该问题有两种方式,一种是借助快速排序思想将最小的前K个数移动到数组前面即可,时间复杂度将会是 O ( n ) O(n) O(n),但是无法适应大数据集场景。另一种思路就是利用最大堆来处理该问题,并可以适应海量数据集场景,其时间复杂度为 O ( n l o g k ) O(nlogk) O(nlogk)

借助快速排序思想的思路如下:

  1. 数组为空或k=0或者k大于数组长度则返回空;
  2. 划分数组,将小数放到数组前面,大数放到数组后面,并得到划分的下标pivot,若pivot不等于k-1则一直循环上述操作;

利用最大堆的思路如下:

  1. 数组为空或k=0或者k大于数组长度则返回空;
  2. 否则初始化最大堆,遍历数组元素,将数组元素依次加入到最大堆,当最大堆大小为k时开始判断,数组元素是否小于堆顶元素,若是则将堆顶元素弹出,将数组元素加入最大堆,那么最后最大堆剩下的k个元素就是数组最小前K个元素。

github链接:JZ29-最小的K个数


C++ 代码

1. 快速排序思想

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

class Solution {
	public:
	    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
	        int size = input.size();
	        if(size == 0 || k == 0 || k > size){
	        	vector<int> ans;
	        	return ans;
			}
			
			int low = 0,high = size-1;
			int pivot = Partition(input,low,high);
			while(pivot != k-1){
				if(pivot > k-1){
					high = pivot-1;
					pivot = Partition(input,low,high);
				}else{
					low = pivot + 1;
					pivot = Partition(input,low,high);
				}
			}
			
			vector<int> ans(k);
			for(int i = 0 ; i < k ; i++){
				ans[i] = input[i];
			}
			return ans;
	    }
	    
	    int Partition(vector<int> &input,int low,int high){
	    	int pivot = input[low];
	    	while(low < high){
	    		while(low < high && input[high] >= pivot){
	    			high--;
				}
				input[low] = input[high];
				while(low < high && input[low] <= pivot){
	    			low++;
				}
				input[high] = input[low];
			}
			input[low] = pivot;
			return low;
		}
};

int main()
{
	int n,k;
	while(cin>>n>>k){
		vector<int> array(n);
		for(int i = 0 ; i < n ; i++){
			cin>>array[i];
		}
		Solution s;
		vector<int> ans = s.GetLeastNumbers_Solution(array,k);
		for(int i = 0 ; i < k ; i++){
			cout<<ans[i]<<" ";
		}
	} 
	
	return 0;
}

2.最大堆思想

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

struct cmp{
	bool operator ()(const int &a,const int &b){
		return a < b;
	}
};

class Solution {
	public:
	    vector<int> GetLeastNumbers_Solution(vector<int> input, int k) {
	        int size = input.size();
	        if(size == 0 || k == 0 || k > size){
	        	vector<int> ans;
	        	return ans;
			}
			vector<int> ans(k);
			priority_queue<int,vector<int> ,cmp> q;
	        for(int i = 0 ; i < size ; i++){
	        	if(q.size() < k){
	        		q.push(input[i]);
				}else{
					if(input[i] < q.top()){
						//cout<<q.top()<<endl; 
						q.pop();
						q.push(input[i]);	
					}else{
						continue;
					}
				}
			}
			for(int i = 0 ; i < k ; i++){
				ans[i] = q.top();
				q.pop();
			}
			return ans;
	    }
};

int main()
{
	int n,k;
	while(cin>>n>>k){
		vector<int> array(n);
		for(int i = 0 ; i < n ; i++){
			cin>>array[i];
		}
		Solution s;
		vector<int> ans = s.GetLeastNumbers_Solution(array,k);
		for(int i = 0 ; i < k ; i++){
			cout<<ans[i]<<" ";
		}
	} 
	
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

daipuweiai

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值