leetcode239.滑动窗口最大值(单调队列或堆)

题目

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

示例 1

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]
解释:
滑动窗口的位置                最大值
---------------               -----
[1  3  -1] -3  5  3  6  7       3
 1 [3  -1  -3] 5  3  6  7       3
 1  3 [-1  -3  5] 3  6  7       5
 1  3  -1 [-3  5  3] 6  7       5
 1  3  -1  -3 [5  3  6] 7       6
 1  3  -1  -3  5 [3  6  7]      7

单调队列解法

单调队列

void push_front(n)//在队头插入n
void push_back(n)//在队尾插入n
void pop_front()//删除队首元素
void pop_back()//删除队尾元素
int front()
int back()

我声明了一个变量 deque<int>window,用于存储下标。这个变量有以下 特点:

  • 变量的最前端(也就是 window.front())是此次遍历的最大值的下标
  • 当我们遇到新的数时,将新的数和双项队列的末尾(也就是window.back())比较,如果末尾比新数小,则把末尾扔掉,直到该队列的末尾比新数大或者队列为空的时候才停止,做法有点像使用栈进行括号匹配。
  • 双项队列中的所有值都要在窗口范围内

特点一只是方便我们获取每次窗口滑动一格之后的最大值,我们可以直接通过 window.front() 获得

通过特点二,可以保证队列里的元素是从头到尾降序的,由于队列里只有窗口内的数,所以他们其实就是窗口内第一大,第二大,第三大… 的数。

特点三就是根据题意设置的。但我们实际上只用比较现在的下标和 window.front() 就可以了,想想为什么?

Answer: 因为只要窗口内第一大元素也就是这个 window.front() 在窗口内,那我们可以不用管第二大第三大元素在不在区间内了。因为答案一定是这个第一大元素。如果 window.front() 不在窗口内,则将其弹出,第二个大元素变成第一大元素,第三大元素变成第二大元素以此类推。

代码编写的过程还要时刻检查队列是否为空防止抛出异常。

时间复杂度

在这里插入图片描述

代码

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n=nums.size();
		deque<int>q;
		for(int i=0;i<k;++i)//i表示滑动窗口的最右侧下标 
		{
			while(!q.empty()&&nums[i]>nums[q.back()])
				q.pop_back();
			q.push_back(i);
		}
		vector<int>result; 
		for(int i=k;i<n;++i)//i表示滑动窗口的最右侧下标 
		{
			while(!q.empty()&&nums[i]>nums[q.back()])
				q.pop_back();
			q.push_back(i);
			if(q.front()<=i-k)
				q.pop_front();
			result.push_back(nums[q.front()]);
		} 
    }

猜你喜欢

转载自blog.csdn.net/weixin_45019830/article/details/115311278