最小的K个数
题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。
思路一
最容易想到的思路就是将输入的n个整数进行从小到大的排序,然后选出前K个数就是最小的K个数,这里选用的是最简单的冒泡排序的算法
时间复杂度:o(n^2)
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<Integer>();
int len = input.length;
if(k > len) return list;
int temp = 0;
for(int i = 0; i < len -1; i++){//控制轮回的次数 len - 1次
for(int j = 0; j < len - 1 - i;j++){
//这里要减i的原因是内层两两比较的边界会随着轮回的次数而减少
//第一次轮回已经找到了最大的数,冒泡到了最后,那么下一次就少一个数了
//这里需要len -1是为了防止后面input[j+1]溢出
if(input[j] > input[j + 1]){
temp = input[j];
input[j] = input[j+1];
input[j+1] = temp;
}
}
}
for(int i = 0; i < k; i++){
list.add(input[i]);
}
return list;
}
}
总结
-
测试用例的周全性:当k的值大于数组的长度
if(k > len) return list;
-
冒泡排序的边界问题,笔者对冒泡还不是很熟悉,所以又仔细分析了一波冒泡,熟悉的可以略过这部分😶
import java.util.ArrayList; import java.util.HashMap; import java.util.Map; public class Test10 { public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) { for(int i = 0; i < input.length; i++){ System.out.print(input[i]+"=>"); } System.out.println("\n"); ArrayList<Integer> list = new ArrayList<Integer>(); int len = input.length; if(k > len) return list; int temp = 0; for(int i = 0; i < len -1; i++){ System.out.println("===========外层循环=============:"+"i="+i); for(int h = 0; h < input.length; h++){ System.out.print(input[h]+"=>"); } System.out.println("\n"); for(int j = 0; j < len - 1 - i;j++){ System.out.println("内层循环:"+"j="+j); System.out.println("input[j]:"+input[j]); System.out.println("input[j + 1]:"+input[j + 1]); if(input[j] > input[j + 1]){ temp = input[j]; input[j] = input[j+1]; input[j+1] = temp; } } } for(int i = 0; i < k; i++){ list.add(input[i]); } return list; } public static void main(String[] args){ Test10 test10 = new Test10(); int[] arr = {4,2,6,1,5}; ArrayList<Integer> list = test10.GetLeastNumbers_Solution(arr,3); for(int i = 0; i < list.size(); i++){ System.out.println(list.get(i)); } } }
4=>2=>6=>1=>5=> ===========外层循环=============:i=0 4=>2=>6=>1=>5=> 内层循环:j=0 input[j]:4 input[j + 1]:2 内层循环:j=1 input[j]:4 input[j + 1]:6 内层循环:j=2 input[j]:6 input[j + 1]:1 内层循环:j=3 input[j]:6 input[j + 1]:5 ===========外层循环=============:i=1 2=>4=>1=>5=>6=> 内层循环:j=0 input[j]:2 input[j + 1]:4 内层循环:j=1 input[j]:4 input[j + 1]:1 内层循环:j=2 input[j]:4 input[j + 1]:5 ===========外层循环=============:i=2 2=>1=>4=>5=>6=> 内层循环:j=0 input[j]:2 input[j + 1]:1 内层循环:j=1 input[j]:2 input[j + 1]:4 ===========外层循环=============:i=3 1=>2=>4=>5=>6=> 内层循环:j=0 input[j]:1 input[j + 1]:2 1 2 4 Process finished with exit code 0
基于堆的实现
-
创建容器:首先创建一个大小为k的数据容器用来存储最小的k个数字
-
读取数据:依次读入n个数,每读一个数之前判断当前容器中的数字个数是否小于k,如果小于,放入容器继续读;如果等于k,找出容器中的最大值和当前读取的数进行比较,如果当前数小就放入容器,如果当前数大就放弃继续读
(这里每次都需要找到当前容器中的最大值,所以我们考虑用最大堆实现)
public ArrayList<Integer> GetLeastNumbers_Solution1(int[] input, int k) {
ArrayList<Integer> result = new ArrayList<Integer>();
int length = input.length;
if(k > length || k == 0){
return result;
}
//通过优先队列构建一个最大堆
PriorityQueue<Integer> maxHeap = new PriorityQueue<Integer>(k, new Comparator<Integer>() {
@Override
public int compare(Integer o1, Integer o2) {
//重新compare方法,实行降序排列 => 最大堆
return o2.compareTo(o1);
}
});
//依次向容器中装入length个数
for (int i = 0; i < length; i++) {
//如果容器中的数小于k,那么就装入
if (maxHeap.size() != k) {
//Inserts the specified element into this priority queue.
maxHeap.offer(input[i]);
//如果容器中的数等于k,那么就需要比较即将装入的数和容器中最大值(根节点)的大小
} else if (maxHeap.peek() > input[i]) {
//remove and return the head of the queue
Integer temp = maxHeap.poll();
temp = null;
//将即将装入的数装进容器堆中
maxHeap.offer(input[i]);
}
}
for (Integer integer : maxHeap) {
result.add(integer);
}
return result;
}
参考
欢迎关注我的公众号:小秋的博客
CSDN博客:https://blog.csdn.net/xiaoqiu_cr
github:https://github.com/crr121
联系邮箱:rongchen633@gmail.com
有什么问题可以给我留言噢~