剑指 Offer 40. 最小的k个数(leetcode每日打卡)
题目描述
输入整数数组 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]
思路
快速排序分组
题目只要求返回最小的 k 个数,对这 k 个数的顺序并没有要求。因此,只需要将数组划分为 最小的 k 个数 和 其他数字 两部分即可,而快速排序的哨兵划分可完成此目标。
根据快速排序原理,如果某次哨兵划分后 基准数正好是第 k+1 小的数字 ,那么此时基准数左边的所有数字便是题目所求的 最小的 k 个数 。
根据此思路,考虑在每次哨兵划分后,判断基准数在数组中的索引是否等于 k ,若 true 则直接返回此时数组的前 kk个数字即可。
若 k < i ,代表第 k+1 小的数字在 左子数组 中,则递归左子数组; 若 k > i ,代表第 k+1 小的数字在 右子数组 中,则递归右子数组; 若 k = i,代表此时 arr[k] 即为第 k+1 小的数字,则直接返回数组前 k 个数字即可;
题解
//输入整数数组 arr ,找出其中最小的 k 个数。例如,输入4、5、1、6、2、7、3、8这8个数字,则最小的4个数字是1、2、3、4。
class Solution {
public int[] getLeastNumbers(int[] arr, int k) {
if(k>=arr.length){return arr;}
return quickSort(arr,0,arr.length-1,k);
}
public int[] quickSort(int[]arr, int left,int right,int k){
int l=left;
int r=right;
int temp=arr[left];
while(l<r){
while(l<r && arr[r]>=temp){
r--;
}
while(l<r && arr[l]<=temp){
l++;
}
swap(arr,l,r);
}
swap(arr,left,l);
if(k>l){return quickSort(arr,l+1,right,k);}
if(k<l){return quickSort(arr,left,l-1,k);}
return Arrays.copyOf(arr,k);
}
public void swap(int[] arr,int i,int j){;
int temp=arr[i];
arr[i]=arr[j];
arr[j]=temp;
}
}
空间复杂度划分函数的平均递归深度为O(logN)
时间复杂度 总体时间复杂度为O(N)
添加备注
执行用时:2 ms, 在所有 Java 提交中击败了97.06%的用户
内存消耗:39.7 MB, 在所有 Java 提交中击败了57.95%的用户
通过测试用例:38 / 38
