题目:
Find the kth largest element in an unsorted array. Note that it is the kth largest element in the sorted order, not the kth distinct element.
For example,
Given [3,2,1,5,6,4] and k = 2, return 5.
Note:
You may assume k is always valid, 1 ≤ k ≤ array’s length.
思路:
非常常规的求无序数组中第k大(小)数。
1. 排序后取第k大,基于比较的排序最优O(lngn)
2.利用快速排序每次将数组分成两个part,与target进行比较,期望数据复杂度O(lgn),最差时间复杂度O(n^2)
3.使用最小堆或最大堆实现O(nlgn) ,可自己实现,也可以直接调用std::make_heap()
4.算法导论第九章,实现了期望及最差情况下为线性复杂度的O(n)算法:PART_SORT按5个一组,把n个数字分为n/5组,每组进行插入排序后,将每组的中位数再组成一个数组,递归调用PART_SORT找到其中位数mo。根据mo将原数组分成leftpart和rightpart。比较mo与target的值,来确定taret是在leftpart中还是rightpart中。继续递归,直到找到第k大的为止。
tips:
make_heap(_First, _Last, _Comp)
默认是建立最大堆的。对int类型,可以在第三个参数传入greater()得到最小堆。
这里暂时只对第二种方法进行实现。之所以写这篇博客,是发现,在快排时,适当优化povit的选择,会对显著提高算法速度…
优化前:
povit直接选择nums[right];
优化后:
povit选择nums[(right+left)/2];即选择中位数。
粗略分析可知,是很大程度上避免了nums为逆序列时造成的O(n^2)的情况!
leetcode提交结果:
快排povit取中位数 beats 98.72% Accepted 10 ms cpp
利用stl模板sort Kth Largest Element in an Array Accepted 12 ms cpp
快排povit取最右端的数 Kth Largest Element in an Array Accepted 28 ms cpp
代码:
class Solution {
public:
// int findKthLargest(vector<int>& nums, int k) {
// sort(nums.begin(),nums.end());
// return nums[nums.size()-k];
// }
int findKthLargest(vector<int>& nums, int k) {
int len = nums.size();
int target = len-k; // 以0开始的数组,第k大=第len-k小
//分治法求第k小的数
int left = 0;
int right = len-1;
while(left<right){
int p=partition(nums,left,right);
if(p == target){
return nums[p];
}
if(p<target){
left = p+1;
}else{
right = p-1;
}
}
return nums[left];
}
int partition(vector<int>& A,int left,int right){
int mid = (left+right)/2;
int key = A[mid];
int temp = A[right];
A[right]=A[mid];
A[mid] =temp;
while(left<right){
while(left<right && A[left]<=key){
++left;
}
if(left<right){
A[right--] = A[left];
}
while(left<right && A[right]>=key){
--right;
}
if(left<right){
A[left++] = A[right];
}
}
A[left] = key;
return left;
}
};