之前讲的都是栈的应用,这次该是队列的应用了。
本题算比较有难度的,需要自己去构造单调队列,建议先看视频来理解。
题目链接/文章讲解/视频讲解:代码随想录
这个题主要思路是用单调队列实现,如果一直在滑动窗口内部排序的话,就是内部最优了,这样的暴力解法时间上没啥优化。但是单调队列可以让滑动窗口内部只保留单调部分元素(本题是求最大值,那么就保持递减,每次pop出第一个元素即为窗口内最大值),这样的操作滑动窗口内部时间复杂度是
,时间复杂度变成线性的了。
Python版本:
Python没有单调队列这个数据类型,于是在deque的基础上重新定义这样一个类。
from collections import deque
class SingleDirQueue:
def __init__(self):
self.queue = deque()
def pop(self, value):
if self.queue and value==self.queue[0]:
self.queue.popleft()
def push(self, value):
while self.queue and value>self.queue[-1]:
self.queue.pop()
self.queue.append(value)
def front(self):
return self.queue[0]
class Solution:
def maxSlidingWindow(self, nums: List[int], k: int) -> List[int]:
queue = SingleDirQueue()
result = []
for i in range(k):
queue.push(nums[i])
result.append(queue.front())
for i in range(k, len(nums)):
queue.pop(nums[i-k])
queue.push(nums[i])
result.append(queue.front())
return result
C++版本:
C++内可以用multiset这个数据类型来实现,也可以自定义一个单调队列的类来实现。以下是自定义版本,multiset版本思路一样,只是que底层数据结构变成直接调用了。
class Solution {
private:
class SingleDirQueue {
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 front() {
return que.front();
}
};
public:
vector<int> maxSlidingWindow(vector<int>& nums, int k) {
SingleDirQueue que;
vector<int> result;
for (int i=0; i<k; i++) {
que.push(nums[i]);
}
result.push_back(que.front());
for (int i=k; i<nums.size(); i++) {
que.pop(nums[i-k]);
que.push(nums[i]);
result.push_back(que.front());
}
return result;
}
};
347.前 K 个高频元素 (一刷至少需要理解思路)
大/小顶堆的应用, 在C++中就是优先级队列
本题是 大数据中取前k值 的经典思路,了解想法之后,不算难。
题目链接/文章讲解/视频讲解:代码随想录
这个题用到了最大最小堆(堆容量为k的,只保留最大的k个元素,最大/最小底层都是一样的)。这里需要保留最大的k个元素,应使用最小堆,每次pop弹出堆内最小的元素,只保留大的元素。两种语言队列里的元素都是item<key, value>, 可以在不同的情况下根据key/value来排序或者选择,都算比较灵活的设计。
Python版本:
python 用heapq实现。
import heapq
class Solution:
def topKFrequent(self, nums: List[int], k: int) -> List[int]:
freq_cnt = {}
for i in range(len(nums)):
freq_cnt[nums[i]] = freq_cnt.get(nums[i], 0) + 1
pri_que = []
for num, freq in freq_cnt.items():
heapq.heappush(pri_que, (freq, num))
if len(pri_que) > k:
heapq.heappop(pri_que)
result = [0] * k
for i in range(k-1, -1, -1):
result[i] = heapq.heappop(pri_que)[1]
return result
C++版本:
C++用priority_queue:优先级队列实现。最小堆底层是二叉树,对于每个parent,子代left>right即可;反之是最大堆。也可以只掌握一个,element取相反数即可。
class Solution {
public:
class minHeap {
public:
bool operator()(const pair<int, int>& lhs, const pair<int, int>& rhs) {
return lhs.second > rhs.second;
}
};
vector<int> topKFrequent(vector<int>& nums, int k) {
unordered_map<int, int> freq_cnt;
for (int i=0; i<nums.size(); i++) {
freq_cnt[nums[i]]++;
}
priority_queue<pair<int, int>, vector<pair<int, int>>, minHeap> pri_que;
for (unordered_map<int, int>::iterator it=freq_cnt.begin(); it!=freq_cnt.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;
}
};
总结
栈与队列做一个总结吧,加油。代码随想录
栈与队列 和数组本质的区别在于是否可以循秩访问,
本文介绍了如何利用单调队列和优先级队列(最小堆)解决编程问题,包括滑动窗口中的最大值查找和前K个高频元素的统计。作者提供了Python和C++的代码示例,强调了栈与队列在数据结构中的应用和区别。
7万+





