算法题:求数组中最小的k个数

说明:本文仅供学习交流,转载请标明出处,欢迎转载!

题目:输入n个整数,找出其中最小的k个数

《剑指offer》给出了两种实现算法:

算法1:采用Partition+递归法,该算法可以说是快速排序和二分查找的有机结合。算法的时间复杂度为O(n),缺点在于在修改Partition的过程中会修改原数组的值。

算法2:采用top-k算法。如果要找最小的K个数,我们才用一个含有K个值的大顶堆;如果要找最大的K个数,我们采用小顶堆。该算法的时间复杂度为O(nlogK),是一种比较好的算法,启发于堆排序。

这里我说明下《剑指offer》在实现上我认为不足的地方:书中用一个基于红黑树的multiset容器来模拟堆,但实际上红黑树是一棵BST,而堆不一定满足BST的特征。虽然用红黑树能得到结果,但是我认为并不是最好的,其实STL中有一个容器适配器priority_queue,其底层的实现数据结构就是一个堆,由于堆是一棵完全二叉树,所以数组的下标与标准定义的左右孩子相对应,所以用基于vector容器的priority_queue的大顶堆我们能够获取最小的K个数。

我的实现代码(用priority_queue):

int* GetMinK(int *arr,int n,int k,int *Result)//用priority_queue实现一个堆
{
	if(!arr || n<1 || k<1 || k>n || !Result)
		return NULL;
	priority_queue<int,vector<int>,less<int> > q;//建一个大顶堆(less),小顶堆(greater)
	int i;
	for(i=0;i<k;i++)//先压入k个元素
	{
		q.push(arr[i]);
	}
	int max=q.top();//获取堆顶元素
	for(i=k;i<n;i++)
	{
		if(arr[i]<max)//如果当前元素比堆顶元素还小
		{
			q.pop();//将堆顶元素删除
			q.push(arr[i]);//并将当前元素压入到堆中
			max=q.top();//更新max值(栈顶元素值)
		}
	}
	i=0;
	while(!q.empty())//将堆中每一个元素的值从堆中弹出,并放入到输出数组中
	{
		Result[i++]=q.top();
		q.pop();
	}
	return Result;
}

《剑指offer》中用multiset容器实现的代码:

#include<iostream>
#include<set>//用到deque容器
#include<iterator>//用到输出迭代器
#include<algorithm>//用到copy函数
#include<functional>//用到仿函数
using namespace std;

int*  GetMinK(int *arr,int n,int k,int *Result)//用红黑树实现
{
	if(!arr || n<1 || k<1 || k>n || !Result)
	{
		cout<<"Invalid Input!";
		return NULL;
	}
	multiset<int,greater<int> >mset(arr,arr+k);//用降序排序
	int i=k;
	multiset<int,greater<int> >::iterator iter;
	for(;i<n;i++)
	{
		iter=mset.begin();
		if(arr[i]<*iter)//如果当前元素小于map中的最大值
		{
			mset.erase(iter);
			mset.insert(arr[i]);
		}
	}
	i=0;
	while(!mset.empty())//将集合中的元素复制到输出数组中后删除
	{
		iter=mset.begin();
		Result[i++]=*iter;
		mset.erase(iter);
	}
	return Result;
}

测试代码:

int main()
{
	int arr[]={1,9,4,3,2,5,6,7,8};
	int n=sizeof(arr)/sizeof(int);
	cout<<"原数组的元素为:";
	copy(arr,arr+n,ostream_iterator<int>(cout," "));
	cout<<endl;
	cout<<"请输入k值:";
	int k;
	while(cin>>k)
	{
		int *result=new int[k];
		result=GetMinK(arr,n,k,result);
		if(result)
		{
			copy(result,result+k,ostream_iterator<int>(cout," "));
		}
		cout<<endl;
		delete []result;
	}
	return 0;
}

测试结果如下:

参考文献------------《剑指offer》

算法题:求数组中最小的k个数,布布扣,bubuko.com

时间: 2024-10-05 21:57:18

算法题:求数组中最小的k个数的相关文章

求数组中最小的k个数

题目:输入n个整数,找出其中最小的K个数.例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,. package test; import java.util.ArrayList; import java.util.Comparator; import java.util.PriorityQueue; import org.junit.Test; public class GetLeastNumbers_Solution { /** * 基于优先队列,时间复杂度为

【算法】数组与矩阵问题——找到无序数组中最小的k个数

1 /** 2 * 找到无序数组中最小的k个数 时间复杂度O(Nlogk) 3 * 过程: 4 * 1.一直维护一个有k个数的大根堆,这个堆代表目前选出来的k个最小的数 5 * 在堆里的k个元素中堆顶的元素是最小的k个数中最大的那个. 6 * 2.接下来,遍历整个数组,遍历过程中看当前数是否比堆顶元素小: 7 * 如果是,就把堆顶元素替换成当前的数,然后从堆顶的位置调整整个堆,让替 8 * 换操作后堆的最大元素继续处在堆顶的位置: 9 * 如果不是,则不进行任何操作,继续遍历下一个数: 10 *

找到无序数组中最小的k个数

题目:给定一个无序整数数组arr,找到其中最小的k个数 要求:如果数组arr的长度为n,排序之后自然可以得到最小的k个数,此时时间复杂度与排序的时间复杂度相同均为O(NlogN),本题要求实现时间复杂度为O(NLogK). 1.O(NLogK)的方法,即一直维护一个有k个数的最大的大根堆,这个堆是目前选出的k个最小数,在堆里的k个元素中堆顶的元素是最大的一个. 接下来遍历整个数组,遍历的过程中看当前数是否比堆顶元素小.如果是,就把堆顶的元素替换成当前的数,然后从堆顶的位置调整堆,替换后堆的最大元

数组中最小的K个数

思路:1.排序,取前k个元素:O(NlogN):2.分治,O(n),利用快排的思想:3.用set 维护最小的k个数,O(NlogK),可处理海量数据. #include <iostream> using namespace std; void print(int *a,int n){ if(a==NULL || n<=0 ) return; for(int i=0;i<n;i++){ cout<<a[i]<<" "; } cout<

小米笔试题:无序数组中最小的k个数

题目描述 链接:https://www.nowcoder.com/questionTerminal/ec2575fb877d41c9a33d9bab2694ba47?source=relative 来源:牛客网 无序数组中最小的k个数 对于一个无序数组,数组中元素为互不相同的整数,请返回其中最小的k个数,顺序与原数组中元素顺序一致. 给定一个整数数组A及它的大小n,同时给定k,请返回其中最小的k个数. 测试样例: [1,2,4,3],4,2 返回:[1,2] 代码 需要保留K个较小的元素,可以删

8.4 找到无序数组中最小的k个数

[题目]: 给定一个无序的整型数组arr,找到其中最小的k个数 [要求]: 如果数组arr的长度为N,排序之后自然可以得到最小的k个数,此时时间复杂度与排序的时间复杂度相同,均为O(NlogN).本题要求读者实现时间复杂度为O(Nlogk)和O(N)的方法 原文地址:https://www.cnblogs.com/latup/p/9982499.html

求一个数组中最小的K个数

方法1:先对数组进行排序,然后遍历前K个数,此时时间复杂度为O(nlgn); 方法2:维护一个容量为K的最大堆(<算法导论>第6章),然后从第K+1个元素开始遍历,和堆中的最大元素比较,如果大于最大元素则忽略,如果小于最大元素则将次元素送入堆中,并将堆的最大元素删除,调整堆的结构; 方法3:使用复杂度为O(n)的快速选择算法..................... /** * Created by elvalad on 2014/12/8. * 输入N个整数,输出最小的K个 */ impor

[程序员代码面试指南]数组和矩阵问题-找到无序数组中最小的k个数(堆排序)

题目链接 https://www.nowcoder.com/practice/6a296eb82cf844ca8539b57c23e6e9bf?tpId=13&tqId=11182&tPage=2&rp=2&ru=/ta/coding-interviews&qru=/ta/coding-interviews/question-ranking 题目描述 从无序序列,找到最小topk个元素. 解题思路 使用大根堆维护最小topk个元素: - 首先前k个元素建立大根堆(从

[经典算法题]寻找数组中第K大的数的方法总结

[经典算法题]寻找数组中第K大的数的方法总结 责任编辑:admin 日期:2012-11-26 字体:[大 中 小] 打印复制链接我要评论 今天看算法分析是,看到一个这样的问题,就是在一堆数据中查找到第k个大的值. 名称是:设计一组N个数,确定其中第k个最大值,这是一个选择问题,当然,解决这个问题的方法很多,本人在网上搜索了一番,查找到以下的方式,决定很好,推荐给大家. 所谓"第(前)k大数问题"指的是在长度为n(n>=k)的乱序数组中S找出从大到小顺序的第(前)k个数的问题.