您的位置:首页 > Web前端

剑指offer——滑动窗口中的最大值

2018-03-22 19:59 281 查看
题目描述:给定一个数组和滑动窗口的大小,请找出所有滑动窗口里的最大值。例如,如果输入的数组为{2,3,4,2,6,2,5,1}即滑动窗口的大小为3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,5}

数组中的滑动窗口滑动窗口中的最大值
[2,3,4],2,6,2,5,14
2,[3,4,2],6,2,5,14
2,3,[4,2,6],2,5,16
2,3,4,[2,6,2],5,16
2,3,4,2,[6,2,5],16
2,3,4,2,6,[2,5,1]5
解题思路:滑动窗口可以看做是一个双端队列,当窗口右移一位的时候,窗口中最左端的数被移出去,原来数组中紧贴窗口右端的数移入窗口中成为窗口中最右端的数。每次找出窗口中最大的数即可。若用暴力方法求解,每次在窗口中遍历一次找到最大值即可。若数组元素个数为n,窗口大小为k,则时间复杂度为O(n*k)。
换一种思路,我们不把滑动窗口的每个数值都存入队列中,而是把有可能成为滑动窗口最大值的数值存放到一个两端开口的队列,接着以输入数组{2,3,4,2,6,2,5,1}为例,数组的第一个数是2,把它存入队列中,第二个数子是3,由于他比2大,因此2不可能成为滑动窗口中的最大值。2先从队列里删除,再把3存到队列中。此时队列中只有一个3。针对第三个数字4,4大于3,3不可能成为最大值,把3从队列里删除,4进队列。此时滑动窗口中已经有3个元素,最大值为4(第一个最大值).接下来处理第四个数字2,2比队列中元素4小,当4滑出去后,2有可能成为窗口中最大值,因此把2存入队列尾部。现在队列中有4和2两个数,4仍然是最大值,4仍然位于队首元素。下一个数字是6,由于它比队列中已有的两个数4和2都大,因此这时4和 2都已经不可能成为窗口中最大值,因此先把4和 2删除,再把6存入队列。下一个数是2,他比6小,如果6滑出后,2有可能成为最大值,所以把2入队。接下来是5,在队列中有6和2,2小于5,因此2不可能是一个滑动窗口的最大值,可以把它从队列中删除,把5入队。数组最后一个数是1,把1存入队列尾部。注意到位于队列头部的数字6是第5个数字,此时的滑动窗口已经不包括这是数字了,因此应该把6删除。怎么知道滑动窗口是否包括一个数字?应该在队列里存数字的数组下标,而不是数值,当 一个数字(一般是当前上次窗口中最大值的下标)的下标与当前处理的数字的下标之差大于或等于滑动窗口大小时,这个数字已经从窗口中删除了,应该从队列中删除。vector<int> maxInWindows(const vector<int> &num, unsigned int size)
{
vector<int> maxInWindows;
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)
{
maxInWindows.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);
}
maxInWindows.push_back(num[index.front()]);
}
return maxInWindows;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  剑指offer