题目地址: https://leetcode-cn.com/problems/zui-xiao-de-kge-shu-lcof/
题目需要在无序的数组中查找出 最小的K个数,并且这K个数不要求有序输出
所以我们只需要得到 小于等于第K+1大 K-1 的数
复杂度分析: 因为我们是要找下标为k的元素,第一次切分的时候需要遍历整个数组 (0 ~ n) 找到了下标是 middle 的元素,假如 k 比 middle 小的话,那么我们下次切分只要遍历数组 (0 ~ k-1)的元素就行啦,反之如果 k 比 middle 大的话,那下次切分只要遍历数组 (k+1~n) 的元素就行啦,总之可以看作每次调用 partition 遍历的元素数目都是上一次遍历的 1/2,因此时间复杂度是 N + N/2 + N/4 + … + N/N = 2N, 因此时间复杂度是 O(N)。
核心的快速排序方法
//主要方法
int[] sort(int[] arr, int low, int high, int k){
int middle = middleSort(arr,low,high);
//如果middle与k相等 就直接返回middle左端的所有元素
if(middle == k){
return Arrays.copyOf(arr,middle + 1);
}
// 否则根据下标middle与k的大小关系来决定继续切分左段还是右段。
return middle > k? sort(arr, low, middle - 1, k)
: sort(arr, middle + 1, high, k);
}
//将middle左右的数组顺序调整好,并返回middle的位置
int middleSort(int[] arr,int low, int high){
//设置初始值为中轴
int middleVal = arr[low];
while(low < high){
//从最右端往左遍历
while(low < high && arr[high] >= middleVal)
high--;
arr[low] = arr[high];
//从最左端往右遍历
while(low < high && arr[low] <= middleVal)
low++;
arr[high] = arr[low];
}
arr[low] = middleVal;
return high;
}
}
最终代码
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
int[] arrMin = new int[k];
if(k == 0 || arr.length == 0) return arrMin;
//使用快排去切分
return sort(arr, 0, arr.length - 1, k - 1);
}
//主要方法
int[] sort(int[] arr, int low, int high, int k){
int middle = middleSort(arr,low,high);
//如果middle与k相等 就直接返回middle左端的元素
if(middle == k){
return Arrays.copyOf(arr,middle + 1);
}
// 否则根据下标j与k的大小关系来决定继续切分左段还是右段。
return middle > k? sort(arr, low, middle - 1, k)
: sort(arr, middle + 1, high, k);
}
//将middle左右的数组顺序调整好,并返回middle的位置
int middleSort(int[] arr,int low, int high){
//设置初始值为中轴
int middleVal = arr[low];
while(low < high){
//从最右端往左遍历
while(low < high && arr[high] >= middleVal)
high--;
arr[low] = arr[high];
//从最左端往右遍历
while(low < high && arr[low] <= middleVal)
low++;
arr[high] = arr[low];
}
arr[low] = middleVal;
return high;
}
}