目录

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. 【51Nod 1238】最小公倍数之和 V3

    http://www.51nod.com/onlineJudge/questionCode.html#!problemId=1238 设\(A(n)=\sum\limits_{i=1}^n\frac{ ...

  2. luogu P1919 【模板】A*B Problem升级版(FFT快速傅里叶)

    模板 嗯 做多项式乘法,进位 没了 #include<cmath> #include<cstdio> #include<cstring> #include<a ...

  3. [CodeForces-763C]Timofey and remoduling

    题目大意: 告诉你一个长度为n的等差数列在模m意义下的乱序值(互不相等),问是否真的存在满足条件的等差数列,并尝试构造任意一个这样的数列. 思路: 首先我们可以有一个结论: 两个等差数列相等,当且仅当 ...

  4. 按考分对学生排序 Exercise08_03

    /** * @author 冰樱梦 * 时间:2018年12月 * 题目:按考分对学生排序 * */ public class Exercise08_03 { public static void m ...

  5. Codeforces Beta Round #7 B. Memory Manager 模拟题

    B. Memory Manager 题目连接: http://www.codeforces.com/contest/7/problem/B Description There is little ti ...

  6. Codeforces Beta Round #6 (Div. 2 Only) D. Lizards and Basements 2 dfs

    D. Lizards and Basements 2 题目连接: http://codeforces.com/contest/6/problem/D Description This is simpl ...

  7. mysql root密码忘了怎么办?

    服务器多起来,密码也就多了,多到自己记不住了,也忘记存哪里了.昨天刚刚下载了KeePass来管理密码,不过为时已晚,我已经忘记了mysql的root密码.好惨好惨,难道还要重装么.还好,有一种方法可以 ...

  8. FreeRTOS Customisation -- FreeRTOSConfig.h

    http://www.freertos.org/a00110.html FreeRTOS is customised using a configuration file called FreeRTO ...

  9. Spring JdbcTemplate batchUpdate() 实例

    在某些情况下,可能需要将一批记录插入到数据库中.如果你对每条记录调用一个插件的方法,SQL语句将被重复编译,造成系统缓慢进行. 在上述情况下,你可以使用 JdbcTemplate BATCHUPDAT ...

  10. UVa-Ecological Premium

    题目地址:http://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem& ...