《剑指offer》刷题——【时间效率】面试题40:最小的K个数(java实现)
一、题目描述
输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是
1,2,3,4,。
二、题目分析
方法一:O(nlogn)
- 把输入的n个整数排序
- 最前面的K个数就是最小的k个数
方法二:基于Partition函数O(n)-允许修改输入的数组
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> GetLeastNumbers_Solution(int [] input, int k) {
ArrayList<Integer> list = new ArrayList<>();
if(input==null || k>input.length || k<=0){
return list;
}
int start = 0;
int end = input.length-1;
int index = Partition(input,start,end);
while(index !=k-1){
if(index > k-1){
end = index-1;
index = Partition(input,start,end);
}
else{
start = index+1;
index = Partition(input,start,end);
}
}
for(int i=0; i<k; i++){
list.add(input[i]);
}
return list;
}
public int Partition(int[] array, int start, int end){
if(array==null || array.length<=0 || start<0 || end>=array.length){
return -1;
}
int pivotIndex = start;
swap(array, start, end);
int small = start-1;
for(pivotIndex=start; pivotIndex<end; pivotIndex++){
if(array[pivotIndex] < array[end]){
small++;
if(small != pivotIndex){
swap(array, pivotIndex, small);
}
}
}
small++;
swap(array, small, end);
return small;
}
public void swap(int[] array, int pivotIndex, int curIndex){
if(pivotIndex!=curIndex){
int temp = array[pivotIndex];
array[pivotIndex] = array[curIndex];
array[curIndex] = temp;
}
}
}
方法三:不修改数组-O(nlogk),适合处理海量数据
- 创建一个大小为k的容器,存储最小的k个数字,每次从输入的n个整数中读取一个数
- 若容器中数字<k,则直接把这次读入的整数放入容器中
- 若容器中数字=k,则容器已满,不能插入,只能替换
- 找出容器中k个数字的最大值
- 比较这次待插入整数和最大值
- 若待插 < 最大值,待插入的数字替换最大值
- 若待插 > 最大值,舍弃此数
- 容器满,有三个操作:1)在k个整数中找到最大数;2)可能在容器中删除最大数;3)可能要插入一个新数字
- 二叉树实现
- 最大堆:由于每次都需要找到k个整数的最大数字,故用最大堆;最大值获取需O(1),插入删除需O(logk)
- 红黑树:红黑树通过把节点分为红黑两种颜色,并根据一些规则确保树上在一定程度上是平衡的,查找、删除、插入都需O(logk)