目录

1 问题描述

2 解决方案

2.1 全部排序法

2.2 部分排序法

2.3 用堆代替数组法

2.4线性选择算法

 


1 问题描述

有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低。


2 解决方案

2.1 全部排序法

先对这n个整数进行快速排序,在依次输出前k个数。

具体代码如下:

package com.liuzhen.array_2;

public class SearchMinK {
//方法1:全部排序
public void quickSort(int[] A,int start,int end){
if(end > start){
int k = LomutoPartition(A,start,end);
quickSort(A,start,k-1);
quickSort(A,k+1,end);
}
}
//返回数值result,满足: 左边部分< A[result] <=右边部分
public int LomutoPartition(int[] A,int start,int end){
if(start >= end)
return start;
int begin = A[start];
int result = start;
for(int i = start + 1;i <= end;i++){
if(A[i] < begin){
result++;
swap(A,i,result);
}
}
swap(A,start,result);
return result;
}
//交换数组m位置和n位置上的值
public void swap(int[] arrayA,int m,int n){
int temp = arrayA[m];
arrayA[m] = arrayA[n];
arrayA[n] = temp;
}
//输出数组前k个元素
public void printArrayK(int[] array,int k){
for(int i = 0;i < k;i++){
System.out.print(array[i]+" ");
}
}
public static void main(String[] args){
SearchMinK test = new SearchMinK();
int[] A = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
test.quickSort(A, 0, A.length-1);
System.out.println("对数组进行排序后结果:");
for(int i = 0;i < A.length;i++)
System.out.print(A[i]+" ");
System.out.println("\n"+"输出数组最小的5个数:");
test.printArrayK(A, 5); }
}

运行结果:

对数组进行排序后结果:
1 1 2 2 3 3 3 4 4 4 5 5 6 6 7 8 9 12 32 34
输出数组最小的5个数:
1 1 2 2 3

2.2 部分排序法

具体操作步骤如下:

(1)遍历n个数,把最先遍历到的k个数存入到大小为k的数组中,假设他们就是最小的k个数;

(2)利用选择排序或交换排序找到这k个元素中的最大值kmax;

(3)继续遍历剩余的n-k个数。假设每次遍历到的新元素的值为x,把x与kmax进行比较:如果x<kmax,则用x替换kmax,并回到第2步重新找出k个元素的数组中新的最大元素kmax;如果x>=kmax,则继续遍历,不更新数组。

具体代码如下:

package com.liuzhen.array_2;

public class SearchMinK {
//方法2:部分排序
public void getArrayMinK(int[] A,int k){
if(k > A.length)
return;
while(true){
int max = getMaxArrayK(A,k); //当前数组前k个元素中的最大值
int count = 0;
for(int i = k;i < A.length;i++){
if(A[max] > A[i])
swap(A,max,i);
else
count++;
}
if(count == A.length-k)
break;
}
System.out.println("\n"+"使用方法2进行部分排序后的结果:");
for(int i = 0;i < A.length;i++)
System.out.print(A[i]+" ");
System.out.println("\n部分排序选出数组中最小的"+k+"个数:");
for(int i = 0;i < k;i++)
System.out.print(A[i]+" ");
} //获取数组前k个元素的最大值的数组下标
public int getMaxArrayK(int[] A,int k){
int result = 0;
if(k > A.length)
return 0;
for(int i = 0;i < k;i++){
if(A[i] > A[result])
result = i;
}
return result;
}
//交换数组m位置和n位置上的值
public void swap(int[] arrayA,int m,int n){
int temp = arrayA[m];
arrayA[m] = arrayA[n];
arrayA[n] = temp;
}
public static void main(String[] args){
SearchMinK test = new SearchMinK(); int[] B = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
test.getArrayMinK(B, 5); }

运行结果:

使用方法2进行部分排序后的结果:
1 1 2 2 3 9 8 7 6 5 4 5 12 32 4 3 3 4 6 34
部分排序选出数组中最小的5个数:
1 1 2 2 3

2.3 用堆代替数组法

此处思想和2.2中一致,唯一区别就是在寻找kmax时,是使用堆排序的思想。

具体代码如下:

package com.liuzhen.array_2;

public class SearchMinK {
//方法3:用堆来代替数组
/*
* 函数功能:对数组A前k个元素进行堆排序
*/
public void heapBottomUp(int[] A,int k){
for(int i = (k-1)/2;i >= 0;i--){
int temp = i;
int tempV = A[temp];
boolean heap = false;
while(!heap && 2*temp < k-1){
int j = 2*temp + 1;
if(j < k-1){
if(A[j] < A[j+1])
j = j + 1;
}
if(tempV >= A[j])
heap = true;
else{
A[temp] = A[j];
temp = j;
}
}
A[temp] = tempV;
}
} public void getArrayMinK2(int[] A,int k){
heapBottomUp(A,k);
while(true){
int count = 0;
for(int i = k;i < A.length;i++){
if(A[i] < A[0]){
swap(A,i,0);
heapBottomUp(A,k);
}
else
count++;
}
if(count == A.length-k)
break;
}
System.out.println("\n"+"使用方法3进行部分堆排序后的结果:");
for(int i = 0;i < A.length;i++)
System.out.print(A[i]+" ");
System.out.println("\n部分排序选出数组中最小的"+k+"个数:");
for(int i = 0;i < k;i++)
System.out.print(A[i]+" ");
}
//交换数组m位置和n位置上的值
public void swap(int[] arrayA,int m,int n){
int temp = arrayA[m];
arrayA[m] = arrayA[n];
arrayA[n] = temp;
}
public static void main(String[] args){
SearchMinK test = new SearchMinK(); int[] D = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
test.getArrayMinK2(D, 5); }
}

运行结果:

使用方法3进行部分堆排序后的结果:
3 2 2 1 1 9 8 7 6 5 4 5 12 32 4 3 3 4 6 34
部分排序选出数组中最小的5个数:
3 2 2 1 1

2.4线性选择算法

看具体代码即可理解其中蕴含的思想。

具体代码如下:

package com.liuzhen.array_2;

public class SearchMinK {
//返回数值result,满足: 左边部分< A[result] <=右边部分
public int LomutoPartition(int[] A,int start,int end){
if(start >= end)
return start;
int begin = A[start];
int result = start;
for(int i = start + 1;i <= end;i++){
if(A[i] < begin){
result++;
swap(A,i,result);
}
}
swap(A,start,result);
return result;
} //方法4:线性选择法
public void getArrayMinK3(int[] A,int k){
int start = 0;
int end = A.length - 1;
int tempK = LomutoPartition(A,start,end);
while(tempK != k){
if(tempK > k){
end = tempK - 1;
tempK = LomutoPartition(A,start,end);
}
if(tempK < k){
start = tempK + 1;
tempK = LomutoPartition(A,start,end);
}
}
System.out.println("\n"+"使用方法4进行快速选择排序后的结果:");
for(int i = 0;i < A.length;i++)
System.out.print(A[i]+" ");
System.out.println("\n部分排序选出数组中最小的"+k+"个数:");
for(int i = 0;i < k;i++)
System.out.print(A[i]+" ");
}
public static void main(String[] args){
SearchMinK test = new SearchMinK(); int[] E = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
test.getArrayMinK3(E, 5);
}
}

运行结果:

使用方法4进行快速选择排序后的结果:
1 2 2 1 3 3 3 4 5 5 4 4 6 8 6 7 9 32 12 34
部分排序选出数组中最小的5个数:
1 2 2 1 3

附4种方法完整代码:

package com.liuzhen.array_2;

public class SearchMinK {
//方法1:全部排序
public void quickSort(int[] A,int start,int end){
if(end > start){
int k = LomutoPartition(A,start,end);
quickSort(A,start,k-1);
quickSort(A,k+1,end);
}
}
//返回数值result,满足: 左边部分< A[result] <=右边部分
public int LomutoPartition(int[] A,int start,int end){
if(start >= end)
return start;
int begin = A[start];
int result = start;
for(int i = start + 1;i <= end;i++){
if(A[i] < begin){
result++;
swap(A,i,result);
}
}
swap(A,start,result);
return result;
}
//交换数组m位置和n位置上的值
public void swap(int[] arrayA,int m,int n){
int temp = arrayA[m];
arrayA[m] = arrayA[n];
arrayA[n] = temp;
}
//输出数组前k个元素
public void printArrayK(int[] array,int k){
for(int i = 0;i < k;i++){
System.out.print(array[i]+" ");
}
} //方法2:部分排序
public void getArrayMinK(int[] A,int k){
if(k > A.length)
return;
while(true){
int max = getMaxArrayK(A,k); //当前数组前k个元素中的最大值
int count = 0;
for(int i = k;i < A.length;i++){
if(A[max] > A[i])
swap(A,max,i);
else
count++;
}
if(count == A.length-k)
break;
}
System.out.println("\n"+"使用方法2进行部分排序后的结果:");
for(int i = 0;i < A.length;i++)
System.out.print(A[i]+" ");
System.out.println("\n部分排序选出数组中最小的"+k+"个数:");
for(int i = 0;i < k;i++)
System.out.print(A[i]+" ");
} //获取数组前k个元素的最大值的数组下标
public int getMaxArrayK(int[] A,int k){
int result = 0;
if(k > A.length)
return 0;
for(int i = 0;i < k;i++){
if(A[i] > A[result])
result = i;
}
return result;
} //方法3:用堆来代替数组
/*
* 函数功能:对数组A前k个元素进行堆排序
*/
public void heapBottomUp(int[] A,int k){
for(int i = (k-1)/2;i >= 0;i--){
int temp = i;
int tempV = A[temp];
boolean heap = false;
while(!heap && 2*temp < k-1){
int j = 2*temp + 1;
if(j < k-1){
if(A[j] < A[j+1])
j = j + 1;
}
if(tempV >= A[j])
heap = true;
else{
A[temp] = A[j];
temp = j;
}
}
A[temp] = tempV;
}
} public void getArrayMinK2(int[] A,int k){
heapBottomUp(A,k);
while(true){
int count = 0;
for(int i = k;i < A.length;i++){
if(A[i] < A[0]){
swap(A,i,0);
heapBottomUp(A,k);
}
else
count++;
}
if(count == A.length-k)
break;
}
System.out.println("\n"+"使用方法3进行部分堆排序后的结果:");
for(int i = 0;i < A.length;i++)
System.out.print(A[i]+" ");
System.out.println("\n部分排序选出数组中最小的"+k+"个数:");
for(int i = 0;i < k;i++)
System.out.print(A[i]+" ");
} //方法4:线性选择法
public void getArrayMinK3(int[] A,int k){
int start = 0;
int end = A.length - 1;
int tempK = LomutoPartition(A,start,end);
while(tempK != k){
if(tempK > k){
end = tempK - 1;
tempK = LomutoPartition(A,start,end);
}
if(tempK < k){
start = tempK + 1;
tempK = LomutoPartition(A,start,end);
}
}
System.out.println("\n"+"使用方法4进行快速选择排序后的结果:");
for(int i = 0;i < A.length;i++)
System.out.print(A[i]+" ");
System.out.println("\n部分排序选出数组中最小的"+k+"个数:");
for(int i = 0;i < k;i++)
System.out.print(A[i]+" ");
}
public static void main(String[] args){
SearchMinK test = new SearchMinK();
int[] A = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
test.quickSort(A, 0, A.length-1);
System.out.println("对数组进行排序后结果:");
for(int i = 0;i < A.length;i++)
System.out.print(A[i]+" ");
System.out.println("\n"+"输出数组最小的5个数:");
test.printArrayK(A, 5);
int[] B = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
test.getArrayMinK(B, 5);
int[] C = {2,9,7,6,5,8};
test.heapBottomUp(C, 6);
System.out.println("\nC数组:");
for(int i = 0;i < C.length;i++)
System.out.print(C[i]+" ");
int[] D = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
test.getArrayMinK2(D, 5);
int[] E = {9,8,7,5,4,3,2,1,6,3,4,5,12,32,3,2,1,4,6,34};
test.getArrayMinK3(E, 5);
}
}

完整代码

算法笔记_035:寻找最小的k个数(Java)的更多相关文章

  1. 算法练习:寻找最小的k个数

    参考July的文章:http://blog.csdn.net/v_JULY_v/article/details/6370650 寻找最小的k个数题目描述:查找最小的k个元素题目:输入n个整数,输出其中 ...

  2. 编程之法:面试和算法心得(寻找最小的k个数)

    内容全部来自编程之法:面试和算法心得一书,实现是自己写的使用的是java 题目描述 输入n个整数,输出其中最小的k个. 分析与解法 解法一 要求一个序列中最小的k个数,按照惯有的思维方式,则是先对这个 ...

  3. 03寻找最小的k个数

    题目描述:查找最小的k个元素         题目:输入n个整数,输出其中最小的k个.         例如输入1,2,3,4,5,6,7和8这8个数字,则最小的4个数字为1,2,3和4. 1:最简单 ...

  4. 算法系列:寻找最大的 K 个数

    Copyright © 1900-2016, NORYES, All Rights Reserved. http://www.cnblogs.com/noryes/ 欢迎转载,请保留此版权声明. -- ...

  5. Java实现寻找最小的k个数

    1 问题描述 有n个整数,请找出其中最小的k个数,要求时间复杂度尽可能低. 2 解决方案 2.1 全部排序法 先对这n个整数进行快速排序,在依次输出前k个数. package com.liuzhen. ...

  6. 寻找最小的k个数(四种方法)

    1 使用从大到小的优先队列保存最小的K个数,每次取出K个数之后的其余数和堆顶元素比较,如果比堆顶元素小,则将堆顶元素删除,将该元素插入 void topK(int arr[],int n,int k) ...

  7. 剑指Offer:面试题30——最小的k个数(java实现)

    问题描述: 输入n个整数,找出其中最小的k个数 思路1: 先排序,再取前k个 时间复杂度O(nlogn) 下面给出快排序的代码(基于下面Partition函数的方法) public void Quic ...

  8. 算法练习-寻找最小的k个数

    练习问题来源 https://wizardforcel.gitbooks.io/the-art-of-programming-by-july/content/02.01.html 要求 输入n个整数, ...

  9. 寻找最小的k个数

    1. 能想到的最直接的办法,就是对数组进行排序,最好的排序算法的时间复杂性为O(n*logn),这一个方法请参照各种排序算法. 2. 另外申请一个k空间数组,依次更改里面的最大值,每做一次最多要扫描一 ...

随机推荐

  1. java 软引用,弱引用,强引用

    韩梦飞沙  韩亚飞  313134555@qq.com  yue31313  han_meng_fei_sha 强引用 ,有用的对象. 强引用 不会被回收. 软引用,有用 但不是必须的对象. 系统在发 ...

  2. POJ3710 Christmas Game 博弈论 sg函数 树的删边游戏

    http://poj.org/problem?id=3710 叶子节点的 SG 值为0:中间节点的SG值为它的所有子节点的SG值加1后的异或和. 偶环可以视作一个点,奇环视为一条边(连了两个点). 这 ...

  3. Test20171009 考试总结 NOIP模拟赛

    题目难度合适,区分度适中,但是本人水平不佳,没有拿到满意的分数. T1(matrix) 一种比较容易想到的想法是枚举起点求出最长全1串做预处理,这是O(n^2)的. 接着枚举列起点,列终点,通过后缀和 ...

  4. spark1.0.0 mllib机器学习库使用初探

    本文机器学习库使用的部分代码来源于spark1.0.0官方文档. mllib是spark对机器学习算法和应用的实现库,包括分类.回归.聚类.协同过滤.降维等,本文的主要内容为如何使用scala语言创建 ...

  5. 对Java Serializable(序列化)的理解和总结(一)

    导读:最近在做项目的过程中,发现一个问题,就是我们最开始的时候,传递参数包括返回类型,都有map类型.但是由于map每次都要匹配key值,很麻烦.所以在之后就将参数传递和返回类型全都改成了实体bean ...

  6. Java Web----Java Web的数据库操作(三)

    Java Web的数据库操作 前面介绍了JDBC技术和JDBC API及API的使用示例,下面详细介绍JDBC在Web中的应用. Java Web----Java Web的数据库操作(一) Java ...

  7. When to use static method in a java class

    First , please understand its feature : * no need to instantiate a instance, i.e. simply you can jus ...

  8. RTL8188EUS带天线的WiFi模块

    http://www.liuliutech.com/ProductShow.asp?ID=121 一,公司介绍瑞昱(REALTEK)半导体成立于1987年,位于台湾[硅谷]的新竹科学园区.凭借着7位创 ...

  9. Linux命令-添加新硬盘,分区及挂载[转]

    http://www.cnblogs.com/qiyebao/p/4484370.html 转自:http://blog.chinaunix.net/uid-25829053-id-3067619.h ...

  10. js复制兼容:ZeroClipboard复制到剪切板(支持IE、FF、Chrome)

    注意:ZeroClipboard在本地测试无法直接使用,必须在服务器上测试,如http://localhost... 准备:ZeroClipboard.swf 和 ZeroClipboard.js 小 ...