代码随想录算法训练营第13天 | LeetCode - 239.滑动窗口最大值,347.前 K 个高频元素,栈和队列总结
239.滑动窗口最大值
题目
![LeetCode 239](2023-02-27T184420.png)
在给定的一个数组中,进行一个大小为k的滑动窗口的移动,将每次移动过程中窗口的最大值保存下来并返回。
自己的思路
暴力法,然后Time Limit Exceeded.
使用一个队列,随着窗口的移动,队列也同时移动,并且队列的队首应该是当前窗口中的最大值。
要实现这样一个数据结构,需要自己定义一个队列并进行维护。这个队列只需要维护可能成为最大值的元素,保证队列里的元素从大到小进行排列。
在pop时,如果窗口移出的元素等于单调队列的出口元素,则将该元素从队列弹出,否则不进行任何操作;在push时,若窗口加入的元素大于队尾元素,则将队尾的元素依次取出,直到对空或队尾元素大于窗口加入的元素,再将该元素push入队。这样操作后,队首即为当前窗口的最大值。
为了实现这样一个数据结构,即满足需要在队首队尾进行操作的条件,使用deque来实现这个队列最合适。 关于deque和queue的区别,可以参照这个文章
解法
1 |
|
该方法的时间复杂度为\(O(n)\),空间复杂度为\(O(k)\)。
347.前 K 个高频元素
题目
![LeetCode 347](2023-02-27T193801.png)
给定一个数组和一个数字K,返回在该数组中出现频率最高的前k个数字。
自己的思路
统计元素的出现次数可以使用map来实现,而按照出现次数来排列前k个元素可以使用优先级队列。
为什么不用快排来对所有出现的元素的频率进行排序?因为我们最后只求前k个,可以只维护前k个可能的元素就好。
优先级队列在默认情况下是使用大顶堆进行排序,在这个题目中,如果每次更新大顶堆时,都将最大的元素弹出,不能保留高频元素。所以要使用小顶堆,将最小的元素弹出,剩下的才是最大的元素。
解法
1 |
|
栈和队列总结
理论基础
栈和队列都是容器适配器,其底层实现可以有:
vector
deque
list
不同的实现方式,对于数据的实际存储方式是有影响的。C++中,栈和队列的默认底层实现都是deque。
栈与队列相互实现
例如用栈来实现队列,用队列来实现栈,这种题目考察的是对于栈和队列特性的了解和使用。
例题:
括号匹配问题
这是使用栈来解决的经典问题。
例题:
字符串去重
将字符串按顺序放到一个串中,若要放入的字符与栈顶相同,就丢弃这两个字符。
例题:
逆波兰表达式
按照逆波兰表达式的顺序求出对应式子的答案,也是栈的经典应用题目。
例题:
滑动窗口最大值
这个题目中一个比较重要的应用是单调队列,即单调递增或单调递减的队列。
例题:
求前k个高频元素
这个题目里面着重讲了优先级队列,优先级队列其实就是个堆,内部元素自动按照元素的权值进行排列。
代码随想录算法训练营第13天 | LeetCode - 239.滑动窗口最大值,347.前 K 个高频元素,栈和队列总结