题目描述
给定整数数组 nums 和整数 k,请返回数组中第 k 个最大的元素。
请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
你必须设计并实现时间复杂度为 O(n) 的算法解决此问题。
示例 1:
输入: [3,2,1,5,6,4], k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6], k = 4
输出: 4
提示:
- 1 <= k <= nums.length <= 105
- -104 <= nums[i] <= 104
快速排序实现快速选择
这道题给了一个特殊的要求就是时间复杂度O(n)
如果抛开这个O(n)复杂度,那么我们可以使用PriorityQueue来维护一个大小为k的最小堆,每次放置一个比堆顶大的数据,这样到最后堆顶数据就是我们要的第k大元素。
回到本地的要求时间复杂度是O(n),如果是这样,那么我们只能遍历几次就要获取到结果
改造快排序方法实现更快的查找
1、根据堆排序,排序一次数组;(从小到大),我们要的位置是n-k
2、查看排序后中间值的位置,如果该位置,小于n-k,则说明结果在偏右部分。如果大于n-k,说明结果在偏左部分。
public int findKthLargest(int[] nums, int k) {
int len =nums.length;
//求k大的数等价于求n-k小的数
return partition(nums,0,len-1,len-k);
}
private int partition(int[] nums, int left, int right, int k) {
//快排的轴数据
int priv=nums[left];
//等待一道重心位置的轴数据位置
int temp =left;
//快排的左指针,每次放置比轴小的数
int cursor=left-1;
for(int i=left;i<=right;i++){
//每次找到比轴小的数都置换
if(nums[i]<=priv){
cursor++;
swapt(nums,cursor,i);
}
}
//将轴放置到位置cursor
swapt(nums,temp,cursor);
//比较查询位置和当前轴的关系,相等返回,大于往右找,小于往左找。
if(k==cursor){
return nums[cursor];
}else if(k>cursor){
return partition(nums,cursor+1,right,k);
}else {
return partition(nums,left,cursor-1,k);
}
}
private void swapt(int[] nums,int a,int b){
int temp = nums[a];
nums[a]=nums[b];
nums[b]=temp;
}
本题的时间复杂度O(kn),能实现题目要求的O(n).
这是一道微软面试题,这道题如果能实现对排序,必然要求面试者优化到O(n)时间复杂度的快排方式。平时不注意这方面训练,这种题挂了基本就无缘微软了。