代码随想录Day13|239. 滑动窗口最大值|347.前 K 个高频元素

239

思路和分析

滑动窗口要求线性复杂度 ,暴力解复杂度只能到N*k,

设计优先级队列,在队列中每次对新进来的元素进行排序,使用大根堆(优先队列)进行或者使用单调队列实现,前者的时间复杂度是O(n*logk)其中 n 是数组的长度,k 是窗口的大小,后者的时间复杂度是O(n).

尝试两种思路和解法:

解法1

大根堆,这个思路从暴力解法上优化而来流程如下

  1. 初始化大根堆:使用一个大根堆来存储窗口中的元素及其在数组中的索引。大根堆根据元素的值进行排序。
  2. 填充初始窗口:将前 k 个元素加入大根堆。
  3. 滑动窗口:遍历数组,对于每个新的窗口位置,执行以下操作:
    • 将新元素加入大根堆。
    • 检查堆顶元素(当前最大值)是否仍在窗口内。如果不在,则将其从堆中移除。这可能需要多次操作,直到堆顶元素在当前窗口内。
    • 将当前堆顶元素(即当前窗口的最大值)添加到结果列表中。
  4. 返回结果:返回包含每个窗口最大值的列表。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
class Solution {
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
vector<int> result;
// 大根堆,存储(元素值,元素索引)对
priority_queue<pair<int, int>> pq;

// 初始化大根堆
for (int i = 0; i < k; ++i) {
pq.push({nums[i], i});
}
result.push_back(pq.top().first);

// 遍历数组
for (int i = k; i < nums.size(); ++i) {
pq.push({nums[i], i});
// 确保堆顶元素在当前窗口内
while (pq.top().second <= i - k) {
pq.pop();
}
result.push_back(pq.top().first);
}

return result;
}
};

大根堆存储了元素值和它们在原数组中的索引。这样可以在窗口滑动时检查堆顶元素是否仍在窗口内。如果堆顶元素的索引不在当前窗口范围内,就将其从堆中移除。

解法2

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
class Solution {
private:
class Myqueue{ //单调队列,首元素必为最大值
public:
deque<int> que;
void pop(int value){
if(!que.empty()&&value ==que.front()){
que.pop_front();
}
}
void push(int value){
while(!que.empty()&&value >que.back()){
que.pop_back();
}
que.push_back(value);
}
int get_max(){
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
Myqueue que;
vector <int> result;
for(int i=0;i<k;i++){
que.push(nums[i]);
}
result.push_back(que.get_max());
for(int i=k;i<nums.size();i++){
que.pop(nums[i-k]);
que.push(nums[i]);
result.push_back(que.get_max());
}
return result;
}
};

实时对队列中的最大值进行维护,更新,所有的值只用读一次。

这里面其实一开始感到迷惑的点是怎么判断单调队列里的最大值是原来的顺序里的哪一个,但是手推一遍之后发现,其实在自定义的pop里面用值判断已经巧妙的掠过了这个问题,整体解法基本学会。

347

思路分析

先用一个map把kv值存起来然后进行频率统计,然后再进行排序找到靠前的部分,但是排序部分可以用小顶堆实现

解法

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
class Solution {
public:
class mycomparison{
public:
bool operator()(const pair<int,int>& IHS,const pair<int, int>&rhs){
return IHS.second >rhs.second;
}

};
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> map;
for(int i=0;i<nums.size();i++){
map[nums[i]]++;
}
priority_queue<pair<int,int>,vector<pair<int,int>>,mycomparison> pri_que;
for(unordered_map<int,int>::iterator it=map.begin();it!=map.end();it++){
pri_que.push(*it);
if(pri_que.size()>k){
pri_que.pop();
}
}
vector<int> result(k);
for(int i=k-1;i>=0;i--){
result[i]=pri_que.top().first;
pri_que.pop();
}
return result;
}

};