输入整数数组 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]
方法一:快排后返回数组
1.1直接使用Arrays.sort()方法对数组进行排序,再用Arrays.copyOf()方法返回数组arr中最小的k个值。
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
Arrays.sort(arr);//先进行排序
return Arrays.copyOf(arr,k);//再将最小的k个数返回
}
1.2手写快排
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
quickSort(arr,0,arr.length-1);
return Arrays.copyOf(arr,k);
}
public void quickSort(int[]arr,int low,int high){
if(low>=high){//如果low>=high说明数组中只有一个数,直接返回
return;
}
int i=low,j=high;//设置哨兵low和high分别代表分治区域中的最小和最大的数
while(i<j){//只要哨兵没有相遇就一直循环
while(i<j && arr[j]>=arr[low]) j--;//如果右边的数大于基准数,就继续向左遍历下一个
while(i<j && arr[i]<=arr[low]) i++;//如果左边的数小于基准数,就继续向右遍历下一个
swap(arr,i,j);//交换i和j的数值。
}
swap(arr,i,low);//最好把基准数值和low位置的数值交换。这样i就是基准数的下标。
//分治
quickSort(arr,low,i-1);//左递归
quickSort(arr,i+1,high);//右递归
}
public void swap(int[]arr,int i,int j){//交换函数
int t=arr[i];
arr[i]=arr[j];
arr[j]=t;
}
}
方法二:基于快速排序的数组划分
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if(k>=arr.length)//如果k比数组长度还大,直接返回整个数组
return arr;
else
return quickSortk(arr,0,arr.length-1,k);
}
public int[] quickSortk(int[]arr,int low,int high,int k){
int i=low,j=high;
while(i<j){//还是要先进行快速排序
while(i<j && arr[j]>=arr[low]) j--;
while(i<j && arr[i]<=arr[low]) i++;
swap(arr,i,j);
}
swap(arr,i,low);
//每次快排之后要检查k是否和i相等了,如果相等,就可以直接确定从0到i为最小的k个数。
if(i<k){
quickSortk(arr,i+1,high,k);//如果i<k,说明还要向右递归去找那剩下的k-i个数
}
if(i>k){//如果i>k,说明k个数都在i的范围里面,需要向左递归找到i里面最小的k个数。
quickSortk(arr,low,i-1,k);
}
return Arrays.copyOf(arr,k);//如果i==k,就可以返回这个数组中的k个数了,这里我觉得k和i都可以,但是用i提交却不行,为什么呢?先留在这个,请各位指点。
}
public void swap(int[] arr,int i,int j){
int t=arr[i];
arr[i]=arr[j];
arr[j]=t;
}
}
方法三:堆,利用java中的优先队列PriorityQueue
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if(k==0||arr.length==0){
return new int[0];//如果k=0或者数组长度为0,就返回一个空数组,不能直接返回arr。why?
}
//优先队列PriorityQueue是二叉小顶堆数据结构实现的,默认是小丁堆,所以要改为大顶堆
Queue<Integer> pq=new PriorityQueue<Integer>((v1,v2)->v2-v1);
for(int num:arr){//遍历arr数组
if(pq.size() < k){//?????????没懂
pq.offer(num);//将num插入(offer)优先队列
}
else if(num<pq.peek()){//如果数值比堆顶元素小,就把堆顶元素移出,把改元素插入堆。
pq.poll();
pq.offer(num);
}
}
int[] res=new int[pq.size()];
int idx=0;
for(int num:pq){
res[idx++]=num;
}
return res;
}
}