题目
输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
解题思路
这题首先最简单的解法是直接对int[]排序, 然后取前K个组成的int[]即可, 但是这里有更好的解法, 使用快速排序,快速排序简单介绍下, 选一个哨兵, 然后将所有比他小的放哨兵左边所有比他大的放右边,这里需要注意的是快拍必须从右边开始,因为我们这里一般选取的哨兵为数组的第一个数字, 理由在代码注释里,然后哨兵的位置可以看成K,如果刚好选的哨兵在K这个地方, 那么后面的排序其实就不需要了, 如果K大于哨兵的位置,说明哨兵的位置到K还没有排序,需要再将将右子串排序下, 如果K小于哨兵的位置,说明K到哨兵的位置还没排序, 需要将左子串在继续排序下, 代码如下。
Java代码实现
import java.util.Arrays;
public class GetLeastNumbers {
public int[] getLeastNumbers(int[] arr, int k) {
if(k >= arr.length){
return arr;
}
quickSort(arr, k, 0, arr.length - 1);
return Arrays.copyOf(arr, k);
}
public void quickSort(int[] arrays, int k, int leftIndex, int rightIndex){
if(leftIndex > rightIndex ){
return;
}
int pivot = arrays[leftIndex];
int l = leftIndex;
int r = rightIndex;
while(l < r){
//是因为基准数定为最左端的6,如果i先出发寻找大于6的数,会先经过1,2等小于6的数;这就会导致最后 i 和 j 相遇时 j 可能并没有找到小于基准数的数,
// 再将i,j同时指向的值与基准数交换,就将大于基准数的值交换到了基准数左边
//举个例子,对于一组数3, 1, 2, 5, 4,如果设3为基准数,先移动 i,则i会在5 处停下,j也在 5 处停下,将5与基准数3交换,
// 得到5, 1, 2, 3, 4,基准数左边有比基准数大的数5
while(arrays[r] >= pivot && l < r){
r --;
}
while(arrays[l] <= pivot && l < r){
l ++;
}
if(arrays[l] > pivot || arrays[r] < pivot){
swap(arrays, r , l);
}
}
swap(arrays, l, leftIndex);
if(l > k) {
quickSort(arrays, k, leftIndex, l - 1);
}
if(l < k){
quickSort(arrays, k,l + 1 , rightIndex);
}
}
private void swap(int[] res, int i, int j) {
int tmp = res[j];
res[j] = res[i];
res[i] = tmp;
}
}