[Description]
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.
[My Answer]
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
return find(0, nums.size()-1, nums, k);
}
private:
int find(int begin, int end, vector<int>& nums, int k) {
if (begin < end) {
int i = begin, j = end, x = nums[begin];
while (i < j)
{
while(i < j && nums[j]<= x) // 从右向左找第一个大于x的数
j--;
if(i < j)
nums[i++] = nums[j];
while(i < j && nums[i]> x) // 从左向右找第一个小于等于x的数
i++;
if(i < j)
nums[j--] = nums[i];
}
nums[i] = x;
if (i+1 > k) {
return find(begin, i-1, nums, k);
} else if (i+1 == k) {
return x;
} else {
return find(i+1, end, nums, k);
}
} else {
return nums[begin];
}
}
};
这道题应用了分治法中的Selection算法。
找到第K大的数字,即每次随机选取一个数字记为v,遍历数组,将数组分成三部分,大于v,等于v和小于v。之后比较各部分的数组长度和k的关系,对相应的部分进行递归,直到找到第k大的数字。如图:
这个方法的复杂度也依赖于每次选中的那个随机数,若每次都选中最差的数字,复杂度会达到O(n^2)。假设随机选择的数字落在数组的1/4~3/4之间为好的选择,好的选择发生的概率是50%,则好的选择发生的期望次数为2次。在两次划分后,被搜索的数组将最多缩减到其原始大小的3/4,由此可得 由这个递推式,可以得到T(n) = O(n),比排序的O(nlogn)要好。
这个方法也可以看做是快速排序的优化,每进行一次划分后都丢弃一部分没用的数据再对剩下的部分进行划分。
在LeetCode上看到了和我算法相同但是代码比我好而且比我快的方法,也贴在下面,他消去了递归的部分,值得学习。
#include <cstdlib>
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
vector<int> bigger, small, equal;
int length;
int pos;
int key;
int jugde;
while (1) {
length = nums.size();
pos = rand() % length;
key = nums[pos];
vector<int>::iterator i = nums.begin();
for (int num = 0; num < length; ++num) {
int now = *(i+num);
if (key == now) {
equal.push_back(key);
} else if (key > now) {
small.push_back(now);
} else {
bigger.push_back(now);
}
}
jugde = k - bigger.size();
// in the equal or small
if (jugde > 0) {
jugde -= equal.size();
// in the small
if (jugde > 0) {
k = jugde;
nums.swap(small);
} else {
// in the equal
return equal[0];
}
} else {
// in the bigger
nums.swap(bigger);
}
bigger.clear();
small.clear();
equal.clear();
}
return nums[0];
}
};