2021-05-03

算法与数据结构:滑动窗口

(第一次发CSDN,有不足之处望轻喷)

题目链接:154. 滑动窗口 - AcWing题库

题目分析:

题目的讲解我只是从最小值的方面去做讲解,最大值可以最小值思路是一样的。

得到这个题目首先我们先用常规的思路去思考一下。我们要求的是在k个数中的最值,首先我们就每次在给定数组中选k个数,然后遍历一次,每次输出最值,然后把第一个去掉,再在后面加上一个新进来的就可以了,下面通过演示来看一下:

例子用的就是题目给出的样例:

 

首先我们选中前3个数字,然后遍历一遍可以得出最小值是-1;

然后我们整体向后移一位,遍历得出最小值是-3;

重复我们的这个操作:

通过暴力可以得出最后的结果是-1 -3 -3 -3 3 3。

代码如下:

#include <iostream>
#include <cstdlib>

using namespace std;

const int Max = 1e6 + 5;
int a[Max];
int b[Max];

int main(int argc, char const *argv[])
{
    int n, k;
    int l = 0, r = 0;
    cin >> n >> k;
    for (int i = 0; i < n; i++)
        cin >> a[i];
    for (int i = 0; i < n; i++)
    {
        int min = 99999999;
        if (l <= r && l < i - k + 1)
            l++;
        b[r++] = a[i];
        if (i > k - 2)
        {
            for (int j = l; j < r; j++)
                min = min < b[j] ? min : b[j];
            cout << min << " ";
        }
    }
    system("pause");
    return 0;
}

上面是暴力的做法,因为这个题目要给出的数据范围是10^6,所以这个算法是肯定不能全过的。

下面我们来做进一下的优化,循环整个数组我们是肯定不能再向下优化了的,我们考虑去优化我们找最值的时候能不能有更快的方法呢?

首先我们看一下第一组数据1 3 -1,当你看到-1的时候前面的数据还有用吗,如果我们保证每次队列的最前面的数据都当前范围最小的,每次我们找最小的时候不就可以缩短成一个O(1)

 

的时间复杂度吗?这里我们就引进了单调队列的思想。

单调队列分为了单调递增和单调递减,可以分为用来求我们的这个题目,而单调队列就是保证队头一定是最值。比如1 3 -1,当有-1的时候就把前面的两个数删除,这样输出队首就是最小值了,这时滑到-3,-3<-1,把-1出队,-3入队,输出队首还是最小值。下面是代码:

#include <iostream>

using namespace std;

const int Max = 1e6 + 5;
int num[Max];       //原数组
int b[Max];

int main()
{
    int n, k;
    int l = 0, r = -1;
    cin >> n >> k;
    for (int i = 0; i < n; i++)
    {
        cin >> num[i];
    }

    //最小值
    for (int i = 0; i < n; i++)
    {
        if (l <= r && b[l] < i - k + 1)     //弹出第一个元素
            l++;
        while (l <= r && num[b[r]] >= num[i])   //维护单调队列
            r--;
        b[++r] = i;
        if (i > k - 2)      //输出
            cout << num[b[l]] << " ";
    }
    cout << endl;

    //最大值
    l = 0, r = -1;
    for (int i = 0; i < n; i++)
    {
        if (l <= r && b[l] < i - k + 1)
            l++;
        while (l <= r && num[b[r]] <= num[i])
            r--;
        b[++r] = i;
        if (i > k - 2)
            cout << num[b[l]] << " ";
    }
    return 0;
}

第一次写,有不足之处望指正。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值