优先级队列
1.最后一块石头的重量

使用优先级队列模拟即可。
cpp
class Solution {
public:
int lastStoneWeight(vector<int>& stones)
{
priority_queue<int> pq;
for (int& e : stones)
pq.push(e);
while (pq.size() > 1)
{
int x = pq.top();
pq.pop();
int y = pq.top();
pq.pop();
if (x > y)
pq.push(x - y);
}
return pq.size() ? pq.top() : 0;
}
};
2. * TopK:数据流中的第K大元素

这道题其实就是TopK问题。TOP-K问题即求数据集合中前K个或第K大最大的元素或者最小的元素,一般情况下数据量都比较大。如果数据量大,不能使用排序解决,因为可能数据不能一次全部加载到内存,排序算法的空间消耗也会很大。
往往是用堆来解决TopK问题。求第K大的元素,创建小堆,控制堆的大小不超过K,把数据集合的元素入堆。当堆的大小为K时,新元素入堆,此时堆的大小为K+1,堆顶元素是这K+1个元素中最小的,即目前第K+1大的元素,此时pop,堆顶元素就是目前第K大的元素。如此遍历数据集合,就能得到前K个最大元素,堆顶为第K大元素。时间复杂度为O(N*logK)。
cpp
class KthLargest {
priority_queue<int, vector<int>, greater<int>> heap;
int _k;
public:
KthLargest(int k, vector<int>& nums)
{
_k = k;
for (int e : nums)
{
heap.push(e);
if (heap.size() > _k)
heap.pop();
}
}
int add(int val)
{
heap.push(val);
if (heap.size() > _k)
heap.pop();
return heap.top();
}
};
3. * TopK:前K个高频单词

用unordered_map或map统计单词出现频次;创建大小为k的堆,频次不同时满足小根堆,频次相同时,按照字典序,应满足大根堆;得到符合要求的前k个单词后,堆顶元素是频次小,字典序大,所以应该从ret数组尾部开始放元素,否则从头开始放元素后逆置数组。
cpp
class Solution
{
typedef pair<string, int> PSI;
struct Greater
{
bool operator()(const PSI& p1, const PSI& p2)
{
if (p1.second == p2.second)
return p1.first < p2.first;
return p1.second > p2.second;
}
};
public:
vector<string> topKFrequent(vector<string>& words, int k)
{
//统计单词频次
map<string, int> m;
for (string& e : words)
m[e]++;
//TopK
priority_queue<PSI, vector<PSI>, Greater> heap;
for (const PSI& psi : m)
{
heap.push(psi);
if (heap.size() > k)
heap.pop();
}
//提取结果
vector<string> ret(k);
for (int i = k - 1;i >= 0;i--)
{
ret[i] = heap.top().first;
heap.pop();
}
return ret;
}
};
4.数据流的中位数

利用大小堆解决。假设数据有序,数据中位数左边用大根堆left维护,右边用小根堆right维护。

如果m == n,则中位数为(left.top()+right.top())/2;如果m>n,即m == n+1,则中位数为left.top()。
每次add()时,对于新加入的数据num,如果m == n,当m为0或num<=left.top()时,直接进left;当num>left.top()时,num进right,此时m<n,再把right.top()放入left中,保持m == n。
如果m>n,当num>=left.top()时,则num直接进right;当num<left.top()时,num进left,此时m == n+2,再把left.top()放入right中保持 m == n+1。
cpp
class MedianFinder
{
priority_queue<int, vector<int>, less<int>> left;
priority_queue<int, vector<int>, greater<int>> right;
public:
MedianFinder()
{
}
void addNum(int num)
{
int m = left.size(), n = right.size();
if (m == n)
{
if (m == 0 || num <= left.top())
left.push(num);
else
{
right.push(num);
left.push(right.top());
right.pop();
}
}
else
{
if (num < left.top())
{
left.push(num);
right.push(left.top());
left.pop();
}
else
right.push(num);
}
}
double findMedian()
{
int m = left.size(), n = right.size();
if (m != n)
return left.top();
else
return (left.top() + right.top()) / 2.0;
}
};