day13:
- 239. 滑动窗口最大值
- 1、(暴力算法)思路:
- 2、(单调队列)思路:
- 347.前 K 个高频元素
239. 滑动窗口最大值
题目链接
状态:暴力ok
文档:programmercarl.com
1、(暴力算法)思路:
一共有两层循环,外层循环(N)迭代变量,内层循环(K)每一个窗口,并计算这个窗口的最大值。时间复杂度O(N*K)。
代码:
class Solution {
public:
//暴力vector<int> maxSlidingWindow(vector<int>& nums, int k) { //短路条件int size = nums.size();//存放结果的数组vector<int> result;if(size == 0) return result;for(int i=0;i<=size-k;i++){//最大值int max = nums[i];for(int j=i;j<=i+k-1;j++){//计算每个窗口内的最大值if(nums[j] > max) max = nums[j];}result.push_back(max);}return result;}
};
2、(单调队列)思路:
可以看到,每移动一次窗口,原理上都是把左边的元素pop出去,右边新加一个元素进来。
但是有时候并不需要去pop那个被窗口抛弃的元素,因为在某些元素push进来之前,我们会先对队列进行一个判断大小的操作:
- 如果要push进来的元素比队列入口处的元素大,那么就要把这些元素一 一pop掉,(因此之后可能就不用去pop那个被窗口抛弃的元素,因为已经被pop掉了)这样就保证了队列是一个单调递减的队列。
- 之后若要pop出口处的元素,那么下一个元素一定是下一个窗口的最大值。
- 并且,若pop的元素==队列出口的元素,那么说明pop的元素是这个窗口的最大值。
代码:
class Solution {
private:class MyQueue{public://定义一个队列que,实现单调队列deque<int> que;// 每次弹出的时候,比较当前要弹出的数值是否等于队列出口元素的数值,如果相等则弹出。// 如果不相等的话说明此时要pop的数比出口数小,在出口数push前该数就已经被pop了。// 同时pop之前判断队列当前是否为空。void pop(int value){if(!que.empty() && value == que.front())que.pop_front();}// 如果push的数值大于入口元素的数值,那么就将队列后端的数值弹出,直到push的数值小于等于队列入口元素的数值为止。// 这样就保持了队列里的数值是单调从大到小的了。void push(int value){while(!que.empty() && value > que.back())que.pop_back(); // 把小的数都pop//小的数pop完再push新的大的数que.push_back(value);}// 返回窗口最大值int getWindowMax(){return que.front();}};
public:vector<int> maxSlidingWindow(vector<int>& nums, int k) {MyQueue que;vector<int> result;//先把前k个数放到que中for(int i=0;i<k;i++){que.push(nums[i]); // 已经保证现在的队列是一个单调队列了}// 此时已经产生了一个窗口的最大值,记录下来result.push_back(que.getWindowMax()); // 窗口移动时,左边的元素被移除,右边的元素会新加进来for(int j=k;j<nums.size();j++){// 左边的元素移除掉que.pop(nums[j-k]);// 右边的元素加进来que.push(nums[j]);// 形成了新的窗口,返回窗口的最大值result.push_back(que.getWindowMax()); }return result;}
};
注意:
在push函数中,判断要加进来的value是否>队列入口处的值时,因为这个比较次数是不确定的,所以不能用if判断,而要用while判断才行。