在未排序的数组中找到第 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
说明:
你可以假设 k 总是有效的,且 1 ≤ k ≤ 数组的长度。
解决方案:
方法一:
首先使用快速排序把数组从大到小进行排序,然后从排好序的数组中找出第k大的值,代码如下:
class Solution {
public:
vector<int> QuickSort(vector<int> s)
{
int len = s.size();
if (len <= 1)
return s;
int mid = s[len / 2];
vector<int> left;
vector<int> right;
vector<int> equal;
for (int i = 0; i < len; i++)
{
if (s[i] > mid)
left.push_back(s[i]);
else if (s[i] < mid)
right.push_back(s[i]);
else
equal.push_back(s[i]);
}
vector<int> left_final = QuickSort(left);
vector<int> right_final = QuickSort(right);
vector<int> res;
res.insert(res.end(), left_final.begin(), left_final.end());
res.insert(res.end(), equal.begin(), equal.end());
res.insert(res.end(), right_final.begin(), right_final.end());
return res;
}
int findKthLargest(vector<int>& nums, int k) {
vector<int> res = QuickSort(nums);
return res[k-1];
}
};
由于本人是小白,快速排序写的十分的繁琐,因此接下来,我会展示一种比较简洁的快速排序方式:左右指针法。
1. 首先选取一个值作为pivot,一般取数组记录中的第一个或者最后一个,这里面选取第一个元素。
2. 设置两个变量,l = left + 1, r = right。其中left是需要处理的数组的最左索引,而right是需要处理的数组的最右索引。
3.从l一直往右走,直到找到一个比pivot小的元素;从r一直往左走,知道找到一个比pivot大的元素,然后交换这两个数的位置。
4.重复第三步,一直往后找,知道 l 和 r 相遇,这是将pivot放置在 r 所在的位置。
其中代码如下:
class Solution {
public:
int PartSort(vector<int> &s, int left, int right)
{
int pivot = s[left];
int l = left + 1, r = right;
while (l <= r)
{
if (s[l]<pivot && s[r]>pivot)
swap(s[l++], s[r--]);
if (s[l] >= pivot)
l++;
if (s[r] <= pivot)
r--;
}
swap(s[left], s[r]);
return r;
}
void QuickSort(vector<int> &s, int left, int right)
{
if (left > right)
return;
int index = PartSort(s, left, right);
QuickSort(s, left, index - 1);
QuickSort(s, index + 1, right);
}
int findKthLargest(vector<int>& nums, int k) {
QuickSort(nums, 0, nums.size()-1);
return nums[k-1];
}
};
方法二:
对于这道题来说,仅仅需要求出第k大的数值,因此没必要把整个数组先排了序再求。因此使用快速排序的核心思想是,每次都要找到一个中枢点pivot,然后遍历其他所有的数字,比如说这道题,将所有大于pivot的值放在中枢点的左边,小于pivot的值放在中枢点的右边,这样子执行一遍排序后,整个数组的第几大的数字就确定了,虽然左右两边不一定是有序的,但是并不影响实验的要求。因此,如果我们求出的中枢点的位置正好是k-1,则直接返回该位置上的数字;如果大于k-1,说明要求的数字在左半部分,更新有边界,再求出新的中枢点进行比较;反之则更新右半部分。
class Solution {
public:
int PartSort(vector<int> &s, int left, int right)
{
int pivot = s[left];
int l = left + 1, r = right;
while (l <= r)
{
if (s[l]<pivot && s[r]>pivot)
swap(s[l++], s[r--]);
if (s[l] >= pivot)
l++;
if (s[r] <= pivot)
r--;
}
swap(s[left], s[r]);
return r;
}
void QuickSort(vector<int> &s, int left, int right)
{
if (left > right)
return;
int index = PartSort(s, left, right);
QuickSort(s, left, index - 1);
QuickSort(s, index + 1, right);
}
int findKthLargest(vector<int>& nums, int k) {
int left = 0, right = nums.size() - 1;
while (true)
{
int index = PartSort(nums, left, right);
if (index == k - 1)
return nums[index];
else if (index > k - 1)
right = index - 1;
else
left = index + 1;
}
}
};