题目:
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。
思路:
最原始的思路是用个数据结构模拟,就用deque,然后最暴力的是扫描过来每一次都找最大值,这样复杂最高,优化一点可以分情况,若新加入的超过max,则无条件迭代他为max,若新加入的没有超过,则又分为旧max弹出和没弹出两种情况。只有在旧max弹出的时候要在deque里面从新扫描最大值。
#include <iostream> #include <deque> #include <vector> #include <algorithm> using namespace std;
//version1__16:34-17:29
class Solution { public: vector<int> maxInWindows(const vector<int>& num, unsigned int size) { vector<int> v; if(size&&size<=num.size()){ deque<int> wind; int max_elem=-9999, i=0; for(;i<size;++i){ wind.push_back(num[i]); max_elem = max(max_elem, num[i]); } v.push_back(max_elem); for(;i<num.size();++i){ int front = wind.front(); wind.push_back(num[i]); wind.pop_front(); if(wind.back() > max_elem){ //尾部插入和头部递增是必要的,然后就是看max的更新,若插入的比max还大,则直接就是新max也不管旧max是否被弹出,若插入的没有max大,则在此基础才判断max是否还在wind中 max_elem = wind.back(); //如在则要在wind中搜新的max,在则什么也不做 }else{ if(front == max_elem){ max_elem = *max_element(wind.begin(), wind.end()); } } v.push_back(max_elem); } } return v; } };
再用别人题解的思路也是这道题最精巧的思路:一个位置对应一个滑动窗(圈出的范围),在一个滑动窗宽度的数据中,最大值为基准,窗口右滑时若max还在窗口里且没有新的max比他更大,则max左端和右端的数据在窗口扫过的范围都是无效的,因为max已经比他们都大了,但又有区别,max坐标的数据是绝对不会用到了,右边的数据在窗口完全划出max时可能是成为新的max的(新增的数据都比旧数据小),所以:max左端是废弃数据,max有段是候选数据,在窗口滑出max时,右端从新找max而且接着的操作都一样,所以抽出来就是往右移动时右边的候选数据代替前边小的数据,维持数据成下降趋势的节点,这里不是存数据,而是存数据的下标。然后一开始是没有考虑窗口左边界,窗口越来越大,当有边界则每次右移后判断窗口左界,用窗口长度定出界后直接pop界外。
//17:29-19:13
class Solution2 { public: vector<int> maxInWindows(const vector<int>& num, unsigned int size) { vector<int> v; deque<int> wind;//里面存的是num的下标,不是num的值,因为会用到下标确定边界,同时有可以映射取出数值 for(int i=0;i<num.size();++i){ while(wind.size()&&num[wind.back()]<num[i]){//取值 wind.pop_back(); } wind.push_back(i);//下标 if(i+1>=size){//要输出 while (wind.size()&&wind.front()<((i+1)-size)){//下标,int型的deque wind.front取出int刚好可以和条件做判断,空取出0 wind.pop_front(); //也可以改为if pop一次,只移动一个单位,或者最直接用外层判断,被临界条件0卡住,测试用例第一个就是0,导致溢出,自己没有样例又不知道 } if(wind.size()){//这里也要单独判wind空,因为他的空是因为size导致整个流程失常:在wind有一个元素的时候会在上面那个循环pop掉导致下面没有,本来是不会到下面来的 v.push_back(num[wind.front()]); } } } return v; } };
这里坑太多了,stl用的时候end要注意,front也要注意,同时容器为空时取出的数据也要注意(deque.front空取出0)。然后还有下标边界条件的坑,下标与数值混用,还有测试数据一开始就是用了个0的异常边界导致程序溢出测试样例又没有提示。。。超出边界程序倒是自动兼容了,但0的就很赋值的误差。