用小根堆的思路:
首先建立一个由最大k个元素形成的小根堆,add元素时进行比较,如果元素小雨堆顶元素,则直接返回堆顶元素,如果大于等于堆顶元素,就删除堆顶节点,并将add的元素插入堆。插入删除时间复杂度均为O(logn)。
建堆的过程比较复杂,首先要考虑初始的nums数组大小与k的关系,如果大于k则直接建堆,后续只需要比较就好了,如果小于k(k-1),则要第一次add的时候先建堆。
删除堆顶元素:将堆顶元素值令为堆尾元素值(因为堆用数组表示(数组下标开始为1),所以堆尾就是下标为k,堆顶就是下标为1),然后从上往下规约。规约也很简单,与左右儿子(与父节点下标n的关系为2n和2n+1)比大小,如果大于儿子,则交换,直至换至堆底。
添加元素:将add的元素直接令为堆尾巴,然后从下向上规约,即于父节点比较(子节点j,父节点则为j/2),如果子节点小于父节点则交换,直至换至堆顶。
附代码
#include <iostream>
#include <vector>
using namespace std;
class KthLargest
{
public:
int num;
int countnum=0;
vector<int> minHeap;
KthLargest(int k, vector<int>& nums)
{
num=k;
minHeap.resize(k+1);
minHeap[0]=-1;
int guodu;
int j; //j用来插入节点时维护堆
//如果初始化的数组大小小于要求的k项
if(nums.size()<=k)
{
for(int i=0;i<nums.size();i++)
{
j=i+1;
minHeap[j]=nums[i];
while (j/2 > 0 && minHeap[j] < minHeap[j/2])
{
// 自下往上堆化
guodu=minHeap[j/2];
minHeap[j/2]=minHeap[j];
minHeap[j]=guodu;
j = j/2;
}
countnum++;
}
}
//如果初始化的数组大小大于要求的k项
else
{
countnum=k;
//先建立一个k个元素的小根堆(用最大的k个元素)
for(int i=0;i<k;i++)
{
j=i+1;
minHeap[j]=nums[i];
while (j/2 > 0 && minHeap[j] < minHeap[j/2])
{
// 自下往上堆化
guodu=minHeap[j/2];
minHeap[j/2]=minHeap[j];
minHeap[j]=guodu;
j = j/2;
}
}
for(int i=0;i<nums.size()-k;i++)
{
if(nums[i+k]>=minHeap[1])
{
//删除顶点
minHeap[1]=minHeap[num];
int upToDown=1;
int minPos = upToDown;
while (true)
{
minPos = upToDown;
if (upToDown*2 <= num && minHeap[upToDown] > minHeap[upToDown*2])
minPos = upToDown*2;
if (upToDown*2+1 <= num && minHeap[minPos] > minHeap[upToDown*2+1])
minPos = upToDown*2+1;
if (minPos == upToDown)
break;
// swap(a, i, minPos);
guodu=minHeap[upToDown];
minHeap[upToDown]=minHeap[minPos];
minHeap[minPos]=guodu;
upToDown = minPos;
}
//插入新节点
minHeap[num]=nums[i+k];
j=num;
while (j/2 > 0 && minHeap[j] < minHeap[j/2])
{
// 自下往上堆化
guodu=minHeap[j/2];
minHeap[j/2]=minHeap[j];
minHeap[j]=guodu;
j = j/2;
}
}
}
}
}
int add(int val)
{
int guodu;
if(countnum<num)
{
countnum++;
int index=countnum;
minHeap[index]=val;
int j=index;
while (j/2 > 0 && minHeap[j] < minHeap[j/2])
{
// 自下往上堆化
guodu=minHeap[j/2];
minHeap[j/2]=minHeap[j];
minHeap[j]=guodu;
j = j/2;
}
return minHeap[1];
}
else
{
if(val<minHeap[1])
{
return minHeap[1];
}
else
{
//删除顶点
minHeap[1]=minHeap[num];
int i=1;
int minPos = i;
while (true)
{
minPos = i;
if (i*2 <= num && minHeap[i] > minHeap[i*2])
minPos = i*2;
if (i*2+1 <= num && minHeap[minPos] > minHeap[i*2+1])
minPos = i*2+1;
if (minPos == i)
break;
guodu=minHeap[i];
minHeap[i]=minHeap[minPos];
minHeap[minPos]=guodu;
i = minPos;
}
//插入新节点
minHeap[num]=val;
int j=num;
while (j/2 > 0 && minHeap[j] < minHeap[j/2])
{
// 自下往上堆化
guodu=minHeap[j/2];
minHeap[j/2]=minHeap[j];
minHeap[j]=guodu;
j = j/2;
}
return minHeap[1];
}
}
}
};
int main()
{
int k=3;
int val=3;
vector<int> nums;
nums.push_back(4);
nums.push_back(5);
KthLargest* obj = new KthLargest(k, nums);
cout<<obj->add(3)<<endl;
cout<<obj->add(5)<<endl;
cout<<obj->add(10)<<endl;
cout<<obj->add(9)<<endl;
cout<<obj->add(3)<<endl;
return 0;
}