1.数组中第K个最大元素
(1)方法一:堆
维护一个堆,时间复杂度O(nlogk),调整堆O(logk),空间复杂度O(k)
1.小根堆:
堆内只有k容量,一旦超过就把最小的(即队首元素推出),遍历完数组后只剩下最后k大的数,队首元素是第k大数
2.大根堆:
做k-1次删除后,队首元素即为第k大
- stl实现
class Solution {
public:
int findKthLargest(vector<int>& nums, int k) {
//priority_queue<int> a 默认大顶堆
priority_queue<int,vector<int>,greater<int> > heap;//创建一个最小堆
for(int num:nums){
//num是nums[i]不是i
heap.push(num);
if(heap.size()>k)//如果堆中的元素数量大于k,就把最小的推出
heap.pop();
}
return heap.top();//返回队首元素
}
};
- 自创建堆
class Solution {
public:
int findKthLargest(vector<int>nums,int k){
//对前k个元素建成小根堆
for(int i=0;i<k;i++)
swim(nums,i);//nums[0]-nums[k-1]是堆,nums[0]是堆首,从小到大
// 将其后每个元素和堆首元素比较,如果大于,将堆顶去除,加入堆并下沉
for(int i=k;i<nums.size();i++){
if(nums[i]>nums[0]){
swap(nums[i],nums[0]);//只有前k个数是堆,交换即去除
sink(nums,0,k-1);//下沉
}
}
return nums[0];
}
void swim(vector<int>& heap,int i){
//从0-i上升式建堆
if(i<=0)
return;
int j=(i-1)/2;//父节点
while(heap[i]<heap[j]&&i>0){
swap(heap[i],heap[j]);
i=j;
j=(i-1)/2;
}
}
void sink(vector<int>& heap,int i,int N){
//下沉式调整位置 ,N代表heap的容量
int j=2*i+1;//左孩子节点
while(j<=N){
//当左孩子存在时
if(j+1<=N&&heap[j+1]<heap[j])
j++;//右节点也存在并且右节点比左节点小,j表示右节点
if(heap[i]<heap[j]) //父节点比子节点都小,可,tui出循环
break;
swap(heap[i],heap[j]);//大就交换位置
i=j;
j=2*i+1;
}
}
};
(2)方法二:快排
快排适合在确定数据量时寻找第k大的数,如果是动态数据流只能由堆排序算法
1.排好所有的数从小到大,找nums[n-k]为第k大
int partition(int A[],int left,int right){
//排A[right]的数
int i=left,j=right,temp=A[right];
while(i!=j){
while(i<j&&A[i]<=temp){
i++;
}
A[j]=A[i];
while(i<j&&A[j]>temp){
j--;
}
A[i]=A[j];
}
A[i]=temp;
return i;
}
void quickSort(int a[],int left,int right){
if(left<right){
//意味着至少是两个数,如果只有一个数或者left>right无意义
int mid=partition(a,left,right);//最右边的数最终的位置将数组划分为两部分
quickSort(a,left,mid-1);//对左区间排序
quickSort(a,mid+1,right);//对右区间排序
}
return ;
}
int findKthLargest(int* nums, int numsSize, int k){
quickSort(nums,0,numsSize-1);
return nums[numsSize-k];
}
2.当n-k确定后直接返回
int partition(int A[],int left,int right){
//排A[right]的数
int i=left,j=right,temp=A[right];
while(i!=j){
while(i<j&&A[i]<=temp){
i++;
}
A[j]=A[i];
while(i<j&&A[j]>temp){
j--;
}
A[i]=A[j];
}
A[i]=temp;
return i;
}
void quickSort(int a[],int left,int right,int k){
if(left<right){
//意味着至少是两个数,如果只有一个数或者left>right无意义
int mid=partition(a,left,right);//最右边的数最终的位置将数组划分为两部分
if(mid==k)
return ;
quickSort(a,left,mid-1,k);//对左区间排序
quickSort(a,mid+1,right,k);//对右区间排序
}
return ;
}
int findKthLargest(int* nums, int numsSize, int k){
quickSort(nums,0,numsSize-1,numsSize-k);
return nums[numsSize-k];
}