寻找最小的k个数
来源:互联网 发布:app推广 aso优化平台 编辑:程序博客网 时间:2024/06/10 01:32
问题描述:给定n个整数,求出其中最小的k个数。
分析:这是一个经典的问题了,存在多种解法,各个解法的效率不一样,这里我列举四种常见的解法。
解法一:可以将所有的数进行排序,然后直接输出前k个数即可。排序算法有很多,读者可以自己选择,如快速排序。
解法二:利用容器(可以是数组,集合等)实现,
我们可以先遍历k个数存入到大小为k的数组中,然后假设这k个数就是最小的k个数;
对这k个数,利用选择或交换排序找到这k个元素中的最大值kmax(找最大值需要遍历这k个数,时间复杂度为O(k)
);
继续遍历剩余n-k个数。假设每一次遍历到的新的元素的值为x,把x与kmax比较: 如果x<kmax ,用x替换kmax,并回到上一步重新找出k个元素的数组中最大元素kmax;如果x>kmax,则继续遍历不更新数组。
每次遍历,更新或不更新数组的所用的时间为O(k)或O(0)。故整趟下来,时间复杂度为n*O(k)=O(nk)。
解法三:利用堆结构实现:其实这个方法与解法二相似,只不过这里的容器采用堆这个数据结构,之所以用堆是因为建k个节点的初始堆的时间复杂度为O(k),每维护一次的代价为O(logk),这一步比数组的时间复杂度低。
至于后面的都一样,因此这种方法的总时间复杂度为O(nlogk)。
这里我给出详细的Java代码,写法比较通用,读者可以很容易的转换为其他语言实现(代码中下标从1开始存数,下标0忽略)。
import java.util.Scanner;public class Qinkxiao { public static void heapadjust(int H[],int s,int m){ //调整堆 int j,k; int rc=H[s]; for( j=2*s;j<=m;j*=2) { if(j<m && H[j]<H[j+1])++j; if(rc>=H[j])break; H[s]=H[j]; s=j; } H[s]=rc; } public static void createdui(int array[],int k){ //建初始堆 for(int i=k/2;i>=1;--i) heapadjust(array,i,k); } public static void main(String[] args) { int array[]={4,5,9,2,1,5,3,-5,20}; int n=array.length-1; int k=3; System.out.print("n个整数为:"); for(int i=1;i<=n;i++) { System.out.print(array[i]+","); } System.out.println(); createdui(array,k); //建k个节点的初始堆 for(int i=k+1;i<=n;i++) //依次遍历后面的n-k个数 if(array[i]<array[1]) { array[1]=array[i]; heapadjust(array,1,k); } System.out.print("前"+k+"小个整数为:"); for(int i=1;i<=k;i++) System.out.print(array[i]+","); }}
输出结果为:
n个整数为:5,9,2,1,5,3,-5,20,
前3小个整数为:2,1,-5,
解法四:借助快速排序的思想:利用快速排序中的分割函数。可以证明这种方法的时间度为O(n).
具体的Java代码如下:
import java.util.Scanner;public class Qinkxiao { public static int partition(int array[],int low,int high){ //快速排序中的划分方法 int q=array[low]; int m; while(low<high){ while(low<high && array[high]>q)high--; m=array[low];array[low]=array[high];array[high]=m; while(low<high && array[low]<q)low++; m=array[low];array[low]=array[high];array[high]=m; } return low; } public static void main(String[] args) { int array[]={4,5,9,2,1,5,3,-5,20}; int n=array.length; int k=3; System.out.print("n个整数为:"); for(int i=0;i<n;i++) { System.out.print(array[i]+","); } System.out.println(); int start=0,end=n-1; int index=partition(array,start,end); while(index!=k-1) //判断索引位置石佛符合要求 { if(index>k-1 ) { end=index-1; index=partition(array,start,end); } else { start=index+1; index=partition(array,start,end); } } System.out.print("前"+k+"小个整数为:"); for(int i=0;i<k;i++) System.out.print(array[i]+","); }}
输出结果为:
n个整数为:4,5,9,2,1,5,3,-5,20,
前3小个整数为:-5,1,2,
上述四种解法比较:
解法一:思想最简单,就是将数据排序,直接输出前k个数,编程简单,但是时间复杂度较高,适合数据量少的场合。
解法二:编程稍微复杂,时间复杂度略低,可以用于海量数据处理。
解法三:比解法二好一点,时间复杂度又降低了,并且不需要交换原来数组中的顺序,可以用于n很大k很小的场合,尤其是海量数据处理。
解法四:时间复杂度最低,线性时间即可解决,但是编程比较复杂,而且需要交换原来数组中数据的顺序,破坏了原来数组的顺序。
这四种解法,要选择适当的场合使用。解法三和解法四大家要牢牢掌握,可以用于其他类似的题目。
除了上述集中解法,还有其他的解法,比如利用哈希表,红黑树等其他数据结构,这里不再讲述。
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的K个数
- 寻找最小的k个数
- 寻找最小的K个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的 k 个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的k个数
- 寻找最小的K个数
- Java.作业5 银行综合
- JVM参数配置总结
- First
- java 正则过滤
- Windows电脑网络常见故障解决方法
- 寻找最小的k个数
- iOS中内存管理
- <OJ_Sicily>1_D closet pair最近邻点对
- Centos7 SSH密钥登陆及密码密钥双重验证
- 安卓-监听home键
- 侧滑菜单之DragLayout初识
- 结构体中运算符的重载
- Android-Charts,Android图形图表控件
- 一个实例说明PID 参数整定