Leetcode 215. 数组中的第K个最大元素

题目

在未排序的数组中找到第 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退出就不一定了。

posted @ 2020-06-29 14:44  pusidun  阅读(139)  评论(0编辑  收藏  举报