输入整数数组 arr ,找出其中最小的 k 个数。
例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
方法1:排序,再查找。(玩赖)
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
int[] res = new int[k];
Arrays.sort(arr);
for(int i=0;i<k;i++){
res[i] = arr[i];
}
return res;
}
}
方法2:最大堆。java中默认的是最小堆,我们把堆看做是一个容器,最大只能容纳k个元素,具体实现如下:
遍历数组中的每一个元素,
1,如果堆的size小于k,直接把遍历的元素加入到堆中。
2,如果堆的size大于等于k,就要判断当前遍历的元素是否比堆顶元素小,
如果比堆顶元素小,就把堆顶元素给移除,把当前遍历的元素加入到堆中。
如果比堆顶元素大,就跳过。
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
//边界条件的判断
if(arr.length==0 || k == 0){
return new int[0];
}
//创建最大堆
PriorityQueue<Integer> pq = new PriorityQueue<Integer>((num1,num2)->num2-num1);
//先在堆中放数组的前k个元素
for(int i=0;i<k;i++){
pq.offer(arr[i]);
}
//因为是最大堆,也就是堆顶的元素是堆中最大的,遍历数组后面元素的时候,
//如果当前元素比堆顶元素大,就把堆顶元素给移除,然后再把当前元素放到堆中,
for(int i=k;i<arr.length;i++){
if(pq.peek()>arr[i]){
pq.poll();
pq.offer(arr[i]);
}
}
//最后再把堆中元素转化为数组
int[] res = new int[k];
for(int i=0;i<res.length;i++){
res[i] = pq.poll();
}
return res;
}
}
方法3:快排改动一下。
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
int[] res = new int[k];
quickSort(arr, res, k, 0, arr.length - 1);
return res;
}
private void quickSort(int[] arr, int[] res, int k, int left, int right) {
//快排的实现方式有多种,我们选择了其中的一种
int i = left;
int j = right;
// int pivot = arr[left]; 这里使用记录基点值会报错,所以暂时还是不要使用了,下面while中还arr[left]
while (i < j) {
while (i < j && arr[j] >= arr[left]) {
j--;
}
while (i < j && arr[i] <= arr[left]) {
i++;
}
swap(arr, i, j);
}
swap(arr, i, left);
//注意这里,i==j是数组中元素的下标。在i之前的元素都是比i指向的元素小,
//后面的都是比他大。如果i==k,正好i之前的k个元素是我们要找的,也就是
//数组中最小的k个,如果i<k,说明前k个元素不够,我们还要往后再找找。如果
//i>k,说明前k个足够了,我们只需要在start之前找k个即可。
if (i > k) {
quickSort(arr, res, k, left, i - 1);
} else if (i < k) {
quickSort(arr, res, k, i + 1, right);
} else {
//取前面的k个即可
for (int m = 0; m < k; ++m) {
res[m] = arr[m];
}
}
}
//交换数组中两个元素的值
private void swap(int[] arr, int i, int j) {
if (i == j)
return;
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}