题目
在未排序的数组中找到第 k 个最大的元素。请注意,你需要找的是数组排序后的第 k 个最大的元素,而不是第 k 个不同的元素。
示例 1:
输入: [3,2,1,5,6,4] 和 k = 2
输出: 5
示例 2:
输入: [3,2,3,1,2,4,5,5,6] 和 k = 4
输出: 4
解法一:用快排partition思路
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
int l = 0, r = nums.size();
srand(time(NULL));
while(l<r) {
int km = partition(nums, l, r);
if (km == k-1){
return nums[km];
}
else if (km < k-1) {
l = km+1;
}
else {
r = km;
}
}
return -1;
}
private:
// [start, end) privot:nums[start]
int partition(vector<int>& nums, int start, int end) {
if(start == end-1)
return start;
swap(nums[start], nums[rand()%(end-start)+start]);
int i = start, j = end - 1;
int pivot = nums[start];
while(i<j){
while(i<j && nums[j] < pivot) --j;
while(i<j && nums[i] >= pivot) ++i;
if(i<j) {
swap(nums[i], nums[j]);
}
}
swap(nums[start],nums[j]);
return j;
}
};
主要思想:将区间[start, end)中第一个元素作为主元pivot,把该区间分为大于等于主元和小于主元2部分,返回主元所在的下标
我们通过主元所在的位置,就能知道主元是第几大的元素
主义第一个元素应该随机选取,否则最坏情况算法会退化成O(n^2).我们这里partition是左边元素大于主元,右边元素小于主元。所以最坏情况下是数组从小到大已排序好。
拓展:快排的partition有3中写法
#include<vector>
#include<iostream>
using namespace std;
#if 0
/* swap 写法 */
int partition(vector<int>& nums, int lo, int hi) {
int pivot = nums[lo];
int i = lo, j = hi - 1;
while(i < j) {
while(pivot < nums[j] && i < j) --j;
while(pivot >= nums[i] && i < j) ++i;
if(i < j)
swap(nums[i], nums[j]);
}
swap(nums[lo], nums[j]);
return j;
}
/* 覆盖写法 */
int partition(vector<int>& nums, int lo, int hi) {
int pivot = nums[lo];
int i = lo, j = hi - 1;
while(i < j) {
while(nums[j] > pivot && i<j) --j;
nums[i] = nums[j];
while(nums[i] <= pivot && i<j) ++i;
nums[j] = nums[i];
}
nums[j] = pivot;
return j;
}
#endif
/*双下标写法*/
int partition(vector<int>& nums, int lo, int hi) {
int i = lo, j = lo + 1;
int pivot = nums[lo];
while(j < hi) {
if(nums[j] < pivot) swap(nums[j], nums[++i]);
++j;
}
swap(nums[lo], nums[i]);
return i;
}
void quickSort(vector<int>& nums, int lo, int hi) {
if (lo >= hi) return;
int index = partition(nums, lo, hi);
quickSort(nums, lo, index);
quickSort(nums, index + 1, hi);
}
int main() {
vector<int> nums{3,4,2,1,6,7,4};
quickSort(nums, 0, nums.size());
for(auto& i: nums)
cout<<i<<endl;
return 0;
}
前2种写法注意while循环里面--j和++i的顺序不能倒过来。
通过--j退出时,j指向的元素必定可以和pivot交换,通过++i退出就不一定了。