滑动窗口的最大值

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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.  滑动窗口大小为0,什么都不做;

  2. 滑动窗口大小超过数组大小,什么都不做;

  3. 数组元素个数为0,什么都不做;

以上两点需要额外注意!!! 

1.0 版本

时间复杂度是O(n*size)。空间复杂度是O(n)

    vector<int> maxInWindows(const vector<int>& num, unsigned int size)
    {
        vector<int> res;
        unsigned n = num.size();
        if(0 == size || n < size) return res;
        unsigned max = 0;    //max用于记录当前窗口最大元素下标,靠右
        for(unsigned i = 0; i <= n - size; ++i)    //循环变量i用于控制窗口个数
        {
            max = max >= i ? max : i;    //更新下标的值很重要
            for(unsigned j = max; j < n && j <= i+size-1; ++j){
                if(num[max] <= num[j]) max = j;
            }
            res.push_back(num[max]);
        }
        return res;
    }
图1 牛客网运行结果

1.1 版本

相对于1.0版本,优化主要体现在某类情况——如果上一个窗口最大值元素还在在一个窗口中,那么只需要比较上一个窗口最大值元素和新加入的元素值大小,而不需要比较全部。

vector<int> maxInWindows(const vector<int>& num, unsigned int size)
    {
        unsigned n = num.size();    //测得数组元素个数;
        vector<int> res;
        /*守卫代码  处理特例:
        *数组元素个数为0;
        *窗口大小为0;
        *窗口大小大于数组元素个数;
        */
        if(0 == n || 0 == size || n < size) return res;
         
        //找到初始窗口中最大值所对应的下标;
        unsigned indexMax = 0;
        unsigned i;
        for(i = 1; i < size; ++i){
            if(num[i-1] <= num[i]) indexMax = i;
        }
        res.push_back(num[indexMax]);
         
        for(i = 1; i <= n-size; ++i){
            //if else 语句用于找到合适的indexMax;
            if(indexMax >= i){    //如果上一次保留的indexMax处于当前窗口中;
                if(num[indexMax] <= num[i+size-1])
                    indexMax = i+size-1;
            }
            else{    //如果上一次保留的indexMax不在当前窗口中;
                //需要遍历整个窗口获取最大值及其下标;
                indexMax = i;
                for(int j = i+1; j <= i+size-1; ++j)
                    if(num[j-1] <= num[j])indexMax = j;
            }
             
            res.push_back(num[indexMax]);
        }
        return res;
    }

2.0 版本

经过前两个版本的讨论,大道至简。思路如下:使用一个双端队列用于记录数组下标,保证队首元素一定是当前窗口的最大值。将数组遍历一次,每次根据队首元素找到数组元素,保存下来。

时间复杂度为O(n),空间复杂度为O(n)

    vector<int> maxInWindows(const vector<int>& num, unsigned int size)
    {
        vector<int> res;
        if(0 == num.size() || 0 == size || num.size() < size) return res;
        deque<unsigned> dq;    //用于存放数组下标
        for(unsigned i = 0; i < num.size(); ++i){
            //剔除当前窗口较小值
            while(dq.size() && num[dq.back()] <= num[i]) dq.pop_back();
            //队头元素表示的下标不在窗口范围内
            while(dq.size() && i-dq.front()+1 > size) dq.pop_front();
            dq.push_back(i);
            if(i+1 >= size) res.push_back(num[dq.front()]);
        }
        return res;
    }
图2 牛客网运行结果

 

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值