小知识,大挑战!本文正在参与“程序员必备小知识”创作活动
面试题 17.14. 最小K个数
设计一个算法,找出数组中最小的k个数。以任意顺序返回这k个数均可。
示例:
输入: arr = [1,3,5,7,2,4,6,8], k = 4 输出: [1,2,3,4] 提示:
- 0 <= len(arr) <= 100000
- 0 <= k <= min(100000, len(arr))
解题思路
通过快速选择,我们可以将数组划分成两个区间A[l,i],B[i+1,r],A区间的所有元素均小于B区间
- 如果k刚好就是A区间的长度的话,说明我们已经找到了最小的k个数字
- 如果k大于A区间长度的话,说明我们要找的除了整个A区间以外,还有B区间的一部分元素
- 如果k小于A区间长度的话,说明我们需要找的数全部在A区间里面
代码
class Solution {
public int[] smallestK(int[] arr, int k) {
int[] res=new int[k];
int l=0,r=arr.length-1,w=k;
while(l<r){
int i=partition(arr,l,r);
int n=i-l+1;
if(n==k)
{
break;
}else if(n<k){
l=i+1;
k-=n;
}else {
r=i;
}
}
System.arraycopy(arr,0,res,0,w);
return res;
}
public int partition(int[] arr, int l,int r) {
int t=arr[l];
while(l<r)
{
while(l<r&&arr[r]>=t)
r--;
arr[l]=arr[r];
while(l<r&&arr[l]<=t)
l++;
arr[r]=arr[l];
}
arr[l]=t;
return l;
}
}
复制代码
- 时间复杂度:期望为 O(n)
最坏情况下的时间复杂度为 O(n^2)。情况最差时,每次的划分点都是最大值或最小值,一共需要划分 n - 1 次,而一次划分需要线性的时间复杂度,所以最坏情况下时间复杂度为 O(n^2)。
- 空间复杂度:期望为 O(logn),递归调用的期望深度为 O(logn),每层需要的空间为O(1),只有常数个变量。
最坏情况下的空间复杂度为 O(n)。最坏情况下需要划分 n 次,即 partition函数递归调用最深 n−1 层,而每层由于需要 O(1) 的空间,所以一共需要 O(n) 的空间复杂度。