0
点赞
收藏
分享

微信扫一扫

[典型]BM47 寻找第K大-中等

知识点​​堆​​​​分治​​

描述

有一个整数数组,请你根据快速排序的思路,找出数组中第 k 大的数。

给定一个整数数组 a ,同时给定它的大小n和要找的 k ,请返回第 k 大的数(包括重复的元素,不用去重),保证答案存在。要求:时间复杂度 [典型]BM47 寻找第K大-中等_快排,空间复杂度 [典型]BM47 寻找第K大-中等_数组_02数据范围:[典型]BM47 寻找第K大-中等_堆排序_03, [典型]BM47 寻找第K大-中等_堆排序_04,数组中每个元素满足 [典型]BM47 寻找第K大-中等_快排_05

示例1

输入:

[1,3,5,2,2],5,3

复制返回值:

2

复制

示例2

输入:

[10,10,9,9,8,7,5,6,4,3,4,2],12,3

复制返回值:

9

复制说明:

去重后的第3大是8,但本题要求包含重复的元素,不用去重,所以输出9


题解

根据快排的思想的解法

思路:

假设一次快排时的结束索引为i,那么i左边的数都小于等于它,i右边的数都大于等于它。因此,如果我们使用std::greater进行排序,经过一次排序如果索引刚好是k-1,那么这个地方的值就是我们要找的值。如果i < k - 1,那么查找[i+1,right]区间,否则查找[left,i-1]区间,代码如下:

class Solution {
public:

int sort_once(std::vector<int> &v, int left, int right)
{
if (left == right)
{
return left;
}

int key = v[left];
while (left < right)
{
while (v[right] <= key && right > left)
{
right--;
}

if (left == right)
{
break;
}
v[left] = v[right];
while (v[left] >= key && left < right)
{
left++;
}
if (left == right)
{
break;
}
v[right] = v[left];
}
v[left] = key;
return left;
}

int findKth(std::vector<int> input, int n, int k)
{
int left = 0;
int right = n - 1;
int target_index = k - 1;
while (left <= right)
{
int pos = sort_once(input, left, right);
if (pos == target_index)
{
right = pos;
break;
}
else if (pos > target_index)
{
right = pos - 1;
}
else
{
left = pos + 1;
}
}
return input[right];
}
};

看起来很美好,但是,但是,这个方法超时了!!!

看起来使用的是快排+二分,应该很快才对,但是出乎意料的是超时了!!!

使用标准库排序-通过

直接使用标准库的快排进行完全排序,然后去第k-1个数,出乎意料的是100%通过了。说明标准库的快排是做了很多优化的,比我们一般写的快排要快不少。如果不是为了刷题,还是老老实实的用标准库的快排~~

class Solution {
public:
static bool comp(int a, int b){ //重载为递减
if(a > b)
return true;
else
return false;
}
int findKth(vector<int> a, int n, int K) {
sort(a.begin(), a.end(), comp);//sort函数为快排
return a[K - 1];
}
};

使用堆排序进行求解-通过

这道题建一个大小为k的小根堆, 遍历数组, 如果堆不满, 则入堆, 否则做如下判断:

  • 如果堆顶元素大于等于当前元素, 说明这个数一定不会是第k大的, 原因很简单, 堆里面已经有k个数, 且都大于等于堆顶的那个, 因此丢弃;
  • 如果堆顶元素小于当前元素, 去掉堆顶元素, 再把当前元素入堆

注意:

  • 由于不是专门的堆问题,因此我们直接使用std::priority_queue,而不是手写
  • 还有一点可以优化的,就是根据k和n-k的大小确定使用小根堆还是大根堆,k < n-k的时候使用大根堆,否则使用小根堆,这样可以使用较少的空间,特别是数组比较长而K比较小的时候,会节省很多时间以及空间

代码如下:

  int findKth(std::vector<int> input, int n, int k)
{
std::priority_queue<int, std::vector<int>, std::greater<int>> q;
for (int i = 0; i < input.size(); ++i)
{
if (q.size() < k)
{
q.push(input[i]);
}
else
{
int top = q.top();
if (input[i] > top)
{
q.pop();
q.push(input[i]);
}
}
}
return q.top();
}
举报

相关推荐

0 条评论