题目描述:
https://leetcode.com/problems/kth-largest-element-in-an-array/
解决方法:
https://blog.csdn.net/qq_26286193/article/details/80683004
(c++):
runtime : 128ms:
class Solution {
public:
int findKthLargest(vector& nums, int k) {
return findKMax(nums,0,nums.size()-1,k);
}
int Partation(vector & nums, int low, int high){
int pivotkey = nums.at(low);
while(low < high ){
while(low < high && nums.at(high) >= pivotkey)
high--;
nums.at(low) = nums.at(high);
while(low< high && nums.at(low)<= pivotkey)
low++;
nums.at(high) = nums.at(low);
}
nums.at(low) = pivotkey;
return low;
}
int findKMax(vectornums,int low,int high,int k) {
int mid = Partation(nums, low, high);
//包括a[mid]的右半边长度
int length_of_right = high - mid + 1;
if (length_of_right == k) return nums.at(mid);
else if (length_of_right > k) {
//右半边长度比k长,说明第k大的元素还在右半边,因此在右半边找
return findKMax(nums, mid + 1, high, k);
}
else {
return findKMax(nums, low, mid - 1, k - length_of_right);
}
}
};
runtime : 108ms(改进中枢选取为三数取中):
选取左,中,右三个数中居中的那个数作为中枢
class Solution {
public:
int findKthLargest(vector& nums, int k) {
return findKMax(nums,0,nums.size()-1,k);
}
void swap(vector & nums , int one ,int two){
int tmp = nums[one];
nums[one]= nums[two];
nums[two] = tmp;
}
int Partation(vector & nums, int low, int high){
int mid = (high - low)/2 + low;
if( nums[high] < nums[low]){
swap(nums,low,high);
}
if(nums[mid] > nums[high]){
swap(nums,low,high);
}
if(nums[mid] > nums[low]){
swap(nums,low,high);
}
int pivotkey = nums[low];
while(low < high ){
while(low < high && nums.at(high) >= pivotkey)
high--;
nums.at(low) = nums.at(high);
while(low< high && nums.at(low)<= pivotkey)
low++;
nums.at(high) = nums.at(low);
}
nums.at(low) = pivotkey;
return low;
}
int findKMax(vectornums,int low,int high,int k) {
int mid = Partation(nums, low, high);
//包括a[mid]的右半边长度
int length_of_right = high - mid + 1;
if (length_of_right == k) return nums.at(mid);
else if (length_of_right > k) {
//右半边长度比k长,说明第k大的元素还在右半边,因此在右半边找
return findKMax(nums, mid + 1, high, k);
}
else {
return findKMax(nums, low, mid - 1, k - length_of_right);
}
}
};
runtime: 12ms(改进中枢为随机选取):
class Solution {
public:
int findKthLargest(vector& nums, int k) {
return findKMax(nums,0,nums.size()-1,k);
}
int Partation(vector & nums, int low, int high){
srand((unsigned)time(NULL));
int idx = (rand() % (high - low + 1)) + low;
int pivotkey = nums[low];
nums[low] = nums[idx];
nums[idx] = pivotkey;
pivotkey = nums[low];
while(low < high ){
while(low < high && nums.at(high) >= pivotkey)
high--;
nums.at(low) = nums.at(high);
while(low< high && nums.at(low)<= pivotkey)
low++;
nums.at(high) = nums.at(low);
}
nums.at(low) = pivotkey;
return low;
}
int findKMax(vectornums,int low,int high,int k) {
int mid = Partation(nums, low, high);
//包括a[mid]的右半边长度
int length_of_right = high - mid + 1;
if (length_of_right == k) return nums.at(mid);
else if (length_of_right > k) {
//右半边长度比k长,说明第k大的元素还在右半边,因此在右半边找
return findKMax(nums, mid + 1, high, k);
}
else {
return findKMax(nums, low, mid - 1, k - length_of_right);
}
}
};
runtime : 12ms:
class Solution {
public:
int findKthLargest(vector& nums, int k) {
return findKMax(nums,0,nums.size()-1,k);
}
int divide(vector & a, int low,int high) {
//随机选一个元素作为枢纽元素
//左边都是比枢纽元素小的,右边都是比枢纽元素大的
srand((unsigned)time(NULL));
int idx = (rand() % (high - low + 1)) + low;
int tmp = a[low];
a[low] = a[idx];
a[idx] = tmp;
tmp = a[low];
while (low < high) {
while (low= tmp) high--;
if (low < high) {
a[low] = a[high];
low++;
}
while (low < high && a[low] <= tmp) low++;
if (low < high) {
a[high] = a[low];
high--;
}
}
//此时low=high,且low就是枢纽元应该在的位置编号,返回low
a[low] = tmp;
return low;
}
int findKMax(vectornums,int low,int high,int k) {
int mid = divide(nums, low, high);
//包括a[mid]的右半边长度
int length_of_right = high - mid + 1;
if (length_of_right == k) return nums.at(mid);
else if (length_of_right > k) {
//右半边长度比k长,说明第k大的元素还在右半边,因此在右半边找
return findKMax(nums, mid + 1, high, k);
}
else {
return findKMax(nums, low, mid - 1, k - length_of_right);
}
}
};
心得:
快速排序使用了分治法的策略。它的基本思想是,选择一个基准数(一般称之为枢纽元),通过一趟排序将要排序的数据分割成独立的两部分:在枢纽元左边的所有元素都不比它大,右边所有元素都比它大,此时枢纽元就处在它应该在的正确位置上了。
在本问题中,假设有N个数存储在数组a中。我们从a中随机找出一个元素作为枢纽元,把数组分为两部分。其中左边元素都不比枢纽元大,右边元素都不比枢纽元小。此时枢纽元所在的位置记为mid。
如果右半边(包括a[mid])的长度恰好为k,说明a[mid]就是需要的第k大元素,直接返回a[mid]。
如果右半边(包括a[mid])的长度大于k,说明要寻找的第k大元素就在右半边,往右半边寻找。
如果右半边(包括a[mid])的长度小于k,说明要寻找的第k大元素就在左半边,往左半边寻找。
中枢的选取对于算法的效率影响很大,所以一般情况下的,取第一个元素都是不可取的,需要优化,随机选取,或者3数取中。