题目描述
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
示例 1:输入:arr = [3,2,1], k = 2
输出:[1,2] 或者 [2,1]
示例 2:输入:arr = [0,1,2,1], k = 1
输出:[0]
限制:0 <= k <= arr.length <= 100000 <= arr[i] <= 10000
解法一:数组计数
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
int n=arr.length;
int[] nums=new int[10001];
int[] res=new int[k];
for(int i:arr){
nums[i]++;
}
int index=0;
for(int i=0;i<10001;i++){
while(nums[i]>0){
if(index==k){
return res;
}
res[index++]=i;
nums[i]--;
}
}
return res;
}
}
解法二: 快排策略
- 快排的特点是每次确定一个正确的位置且位置的左右分别小于,大于当前索引k的值
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
//边界情况
if (k == 0 || arr.length == 0) {
return new int[0];
}
//快排,得到排好位置的arr
quicksort(arr,0,arr.length-1,k-1);
//复制数组
return Arrays.copyOf(arr,k);
}
public void quicksort(int[] arr,int start,int end,int k){
//开头设定为枢轴
int pivot=arr[start];
//用两个新指针指向开头结尾。
int i=start,j=end+1;
while(true){
//不要超右边界
while(++i<=end&&arr[i]<pivot);
//不要超左边界
while(--j>=start&&arr[j]>pivot);
//最终的i,j大小不一定相等
if(i>=j){
break;
}
swap(arr,i,j);
}
//这里一定是j,因为此时的arr[j]<pivot 可以跟start交换位置,arr[i]>pivot不符合
swap(arr,start,j);
//用j交换就应该用j判断
if(j==k){
return;
}
else if(j<k){
quicksort(arr, j+1,end,k);
}
else{
quicksort(arr, start,j-1,k);
}
}
public void swap(int[] arr,int i,int j){
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
解法三:最大堆
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if (k == 0 || arr.length == 0) {
return new int[0];
}
//最大堆
Queue<Integer> deap=new PriorityQueue<>((o1,o2)->o2-o1);
for(int i:arr){
//不超过k,直接添加
if(deap.size()<k){
deap.add(i);
}
//等于k 看是否小于峰顶,小于就弹出峰顶,加入新值
else if(i<deap.peek()){
deap.poll();
deap.add(i);
}
}
int[] nums=new int[k];
for(int i=0;i<k;i++){
nums[i]=deap.poll();
}
return nums;
}
}