在未排序的数组中找到第 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 ≤ 数组的长度。
思路1:将数组number先排序,然后再返回第K个数组的位置就可以了,时间复杂度为nlogn,n为我们元素的个数
解法1:利用堆来解决
维护一个K大小的最小堆,堆中元素个数小于K时,新元素直接进入堆;否则,当堆顶小于新元素时,弹出堆顶,将新元素加入堆。
解释:由于堆是最小堆,堆顶是堆中最小元素,新元素都会保证比堆顶小(否则新元素替换堆顶),故堆中K个元素是已扫描的元素里最大的K个;堆顶即为第K大的数。
设数组长度为N,求第K大的数,时间复杂度是N*logK
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
std::priority_queue<int, vector<int>,std:: greater<int>> Q;
for(int i = 0; i < nums.size(); i++){
if(Q.size() < k){
Q.push(nums[i]);
}
else if(nums[i] > Q.top()){
Q.pop();
Q.push(nums[i]);
}
}
return Q.top();
}
};
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
vector<int> result(nums.begin(), nums.begin()+k);
buildHeap(result);
for (int i = k; i < nums.size(); i++)
{
if (nums[i] > result[0])
{
result[0] = nums[i];
heapModify(result, 0, result.size());
}
}
return result[0];
}
void heapModify(vector<int>& vec, int index, int heapSize)
{
int leftChild = index * 2 + 1;
int rightChild = index * 2 + 2;
int tmp = index;
while (leftChild < heapSize)
{
if (rightChild < heapSize && COMPARE(&vec[rightChild], &vec[leftChild]) < 0)
{
tmp = rightChild;
}
else
{
tmp = leftChild;
}
if (COMPARE(&vec[index], &vec[tmp]) < 0)
{
break;
}
SWAP(vec, index, tmp);
index = tmp;
leftChild = index * 2 + 1;
rightChild = index * 2 + 2;
}
}
void heapInsert(vector<int>& vec, int value, int index)
{
vec[index] = value;
while (index != 0)
{
int dad = (index - 1) / 2;
if (COMPARE(&vec[index], &vec[dad]) < 0)
{
SWAP(vec, dad, index);
index = dad;
}
else
{
break;
}
}
}
void buildHeap(vector<int>& vec)
{
for (int i = vec.size() / 2 - 1; i >= 0; i--)
{
heapModify(vec, i, vec.size());
}
}
void SWAP(vector<int>& vec, int index1, int index2)
{
int tmp = vec[index1];
vec[index1] = vec[index2];
vec[index2] = tmp;
}
int COMPARE(const void* lhs, const void* rhs)
{
int lhsValue = *((int*)lhs);
int rhsValue = *((int*)rhs);
return lhsValue - rhsValue;
}
};
解法2:利用快速排序思想,对数组进行划分,并且判断划分的边界元素位置mid是否为第k大的数(k - 1);若是则返回该数,若mid > k - 1说明第k大的数在左半边数组里;若mid < k - 1说明在右半边数组里。对其继续进行数组划分,直到找到第k大的数。数组划分函数partation采用数组中心位置的元素值作为bound(边界),也可以采用随机元素,最好不要用第一个(最后一个)元素,防止数组绝大部分元素是有序的,影响查找效率。(转自leetcode题解)
class Solution {
public:
int findKthLargest(vector& nums, int k) {
int low = 0, high = nums.size() - 1, mid = 0;
while (low <= high) {
mid = partation(nums, low, high);
if (mid == k - 1) return nums[mid];
else if (mid > k - 1) high = mid - 1;
else low = mid + 1;
}
// 实际上返回 -1 代表没有第 k 大的数,这里不存在
return -1;
}
int partation(vector& nums, int low, int high) {
int left = low + 1, right = high;
swap(nums[low], nums[(low + high) / 2]);
int bound = nums[low];
// 双指针,快速排序,交换不符合条件的数据
while (left <= right) {
while (left < high && nums[left] >= bound) left++;
while (nums[right] < bound) right--;
if (left < right)
swap(nums[left++], nums[right--]);
else break;
}
// 将bound放到换分完成后的两个数组之间,作为边界, 返回bound的位次
swap(nums[low], nums[right]);
return right;
}
};
作者:liushang-leecode
链接:https://leetcode-cn.com/problems/kth-largest-element-in-an-array/solution/kuai-su-pai-xu-si-xiang-shu-zu-hua-fen-by-liushang/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。