剑指offer(C++)——滑动窗口的最大值

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/YF_Li123/article/details/70256338

题目描述

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}

解法1:暴力解法。扫描每一个滑动窗口的所有数字并找出其中的最大值。如果滑动窗口大小为k,需要O(k)时间找到最大值,对于长度为n的数组,总的时间复杂度为O(nk)。

解法2:换一种思路,我们用一个队列来保存有可能成为滑动窗口最大值的数字,其中队头存放当前窗口的最大值。

对于数组{2,3,4,2,6,2,5,1}来说,

(1)第一个数字是2,把它存入队列。第二个数字是3,它比前一个数字2大,那么2就不可能成为滑动窗口的最大值,于是先把2从队列中删除,再把3存入队列。对于下一个数字4也是如此,最后队列中只有4。此时滑动窗口中已经有3个数字了,而且最大值4位于队列的头部。

(2)下一个数字是2,它比队列中的4小,但是当4滑出窗口以后它就有可能成为最大值,因此我们需要先把它保存起来,存入队列尾部。现在队列中有4和2,4是最大值,位于队列头部。

(3)下一个数字是6,它比队列中的4和2都大,那么4和2就不可能成为滑动窗口最大值了,我们先把4和2从队列尾部删除,然后再把6存入。此时6是最大值,且位于队列头部。

(4)接着是数字2,情况类似于第(2)步。此后队列中有6和2,6为最大值,位于队列头部。

(5)接着是数字5,情况类似于第(3)和第(2)步。此后队列中有6和5,6为最大值,位于队列头部。

(6)接着是最后一个数字1,把1存入队列尾部。注意到此时队列头部的数字6已经不在滑动窗口。因此我们需要把它从队头删除。此时有个问题,就是怎么判断滑动窗口是否包含一个数字呢???解决办法是我们可以将数字在数组中的下标存入队列,而不是数字。当一个数字的下标与当前处理的数字的下标之差大于或者等于滑动窗口大小时,这个数字就已经不在滑动窗口范围内了,可以删除。

综上分析:这个队列需要在头部和尾部都能删除数字,因此我们可以使用STL中的deque来实现。

/*
思路:使用一个两端开口的队列来保存有可能是滑动窗口最大值的数字的下标,队头永远存放当前滑动窗口最大值的下标。
在存入一个数字的下标之前,首先要判断队列里已有数字是否小于待存入的数字,
如果是,那么这些数字已经不可能成为滑动窗口的最大值,因此将它们依次从队尾删除。同时如果队头数字已经从窗口里滑动出去,那么它也要从队头删除
*/
class Solution {
public:
	vector<int> maxInWindows(const vector<int>& num, unsigned int size)
	{
		vector<int> maxValue;
		if (num.size() >= size&&size >=1)
		{
			deque<int> index;
			for (unsigned int i = 0; i < size;i++)
			{
				while (!index.empty() && num[i] >= num[index.back()])     //判断待存入数字是否大于队列中已有数字
					index.pop_back();
				index.push_back(i);
			}
			for (unsigned int i = size;i < num.size();++i)
			{
				maxValue.push_back(num[index.front()]);              //保存前一个(不包括待存入数字)滑动窗口最大值
				while (!index.empty() && num[i] >= num[index.back()])     //判断待存入数字是否大于队列中已有数字
					index.pop_back();
				if (!index.empty() && index.front() <= (int)(i - size))   //判断对头数字是否已经滑出窗口
					index.pop_front();
				index.push_back(i);
			}
			maxValue.push_back(num[index.front()]);                        //保存当前窗口最大值(即最后一个窗口最大值)
		}
		return maxValue;
	}
};


阅读更多
换一批

没有更多推荐了,返回首页