LeetCode-面试题40-最小的k个数
题目
输入整数数组 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 <= 10000
0 <= arr[i] <= 10000
解题思路
方法1、快排+选择:
基于之前快速排序的代码实现,现在加了几个条件,如下:
每快排切分1次,找到切分点,比较切分点和k的关系
- 如果相等则意味着,切分点左边的数字已经是最小数组集合,直接返回
- 如果k小于m说明需要在左子数组进行搜索
- 如果k大于m说明需要在右子数组进行搜索
方法2、最大堆:
使用Java的优先级队列PriorityQueue,实现最大堆
当队列不足k个的时候,传入一个元素
当队列大于k个的时候,判断下一个元素是否小于堆顶,如果小于就把堆顶弹出,把下一个元素传入
之后返回对应的数组
Java代码
java
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if(k==0)
return new int[0];
else if(arr.length<=k)
return arr;
quickSort(arr,0,arr.length-1,k);
int[] res = new int[k];
for(int i = 0;i < k; i++){
res[i] = arr[i];
}
return res;
}
public void quickSort(int[] list, int left, int right,int k) {
// 每快排切分1次,找到切分点,比较切分点和k的关系
int m = partition(list,left,right);
// 如果相等则意味着,切分点左边的数字已经是最小数组集合,直接返回
if(k==m){
return;
}
// 如果k小于m说明需要在左子数组进行搜索
else if(k<m){
quickSort(list,left,m-1,k);
}
// 如果k大于m说明需要在右子数组进行搜索
else{
quickSort(list,m+1,right,k);
}
}
public int partition(int[] list, int left, int right) {
// 用数组的第一个元素作为基准数
int first = list[left];
while (left < right) {
while (left < right && list[right] >= first) {
right--;
}
swap(list, left, right);
while (left < right && list[left] <= first) {
left++;
}
swap(list, left, right);
}
// 返回分割点所在的位置
return left;
}
public void swap(int[] list, int left, int right) {
int temp;
if (list != null && list.length > 0) {
temp = list[left];
list[left] = list[right];
list[right] = temp;
}
}
}
Java代码
java
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if(k==0||arr.length==0)
return new int[0];
// 使用一个最大堆
// 默认最小堆,需要转化,默认是升序的,转化之后是降序的
Queue<Integer> stack = new PriorityQueue<>((v1,v2)->v2-v1);
for(int num:arr){
if(stack.size()<k){
stack.offer(num);
}
// peek队首元素
else if(num<stack.peek()){
// 因为是降序,所以poll队首是最大元素
stack.poll();
stack.offer(num);
}
}
int[] res = new int[stack.size()];
int i = 0;
for(int num:stack){
res[i++] = num;
}
return res;
}
}