滑动窗口最大值

本文详细介绍了如何解决滑动窗口最大值问题,包括四种不同的算法方法:直接比较、优先队列、双向队列和分块。每种方法的时间复杂度和空间复杂度都进行了分析,并给出了具体的代码实现。通过这道题目的深入研究,理解了滑动窗口问题的高效求解策略。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

滑动窗口最大值

Leetode我又回来了

题目描述

给你一个整数数组 nums,有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。

返回滑动窗口中的最大值。

示例 :

输入:nums = [1,3,-1,-3,5,3,6,7], k = 3
输出:[3,3,5,5,6,7]

方法1:(超时)
直接比较每个窗口的数,找出最大值,使用STL自带的*max_element()函数

vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> out;
        int maxnum = 0;
        int length = nums.size();
        if(length==0) return out;
        for(int i = 0 ;i<=length-k;i++)
        {
            maxnum = *max_element(nums.begin()+i,nums.begin()+i+k);
            out.push_back(maxnum);
        }
    return out;
    }

方法2:
使用优先队列priority_queue,优先队列每次弹出最大值,但是需要一个index判断最大值在原数组中的位置,使用pair<int,int>,第二个值为index。
时间复杂度:O(nlogn)
空间复杂度:O(n) (指的是队列的空间复杂度)
由于将一个元素放入优先队列的时间复杂度为O(logn),因此总时间复杂度为O(nlogn)。

    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> out;
        priority_queue<pair<int,int>> window;
        int length = nums.size();
        if(length==0) return out;
        for(int j =0;j<k;j++){
            window.push(make_pair(nums[j],j));}
        for(int i = 0 ;i<=length-k;i++){
            window.emplace(nums[i+k-1],i+k-1);
            while(window.top().second<i ){
                window.pop();}
            out.push_back(window.top().first);
        }
    return out;
    }

方法3:
使用双向队列,队列中存放数组下标。
分为三步:1.比较新加的数与队列尾部指引的数的大小,pop_back队列尾部的小数。push_back新数。
2.判断队首的数是否超出窗口,pop_front过去的数。
3.保存队首的数。
时间复杂度:O(n)
空间复杂度:O(k) (指的是队列的空间复杂度)

    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> out;
        deque<int> window;
        int length = nums.size();
        if(length==0) return out;
        for(int j =0;j<k;j++){
            while(!window.empty() && nums[window.back()]<=nums[j]){
                window.pop_back();
            }
            window.push_back(j);}
        for(int i = k-1 ;i<length;i++){
            if(window.front() <= i-k ){
                window.pop_front();}
            while(!window.empty() && nums[window.back()]<=nums[i]){
                window.pop_back();}
            window.push_back(i);
            out.push_back(nums[window.front()]);
        }
    return out;
    }

方法4:
分块
我们可以将数组从左到右按照 k 个一组进行分组,最后一组中元素的数量可能会不足 k 个。
如果 i不是 k 的倍数,用 prefixMax[i] 表示下标 i对应的分组中,以 i 结尾的前缀最大值;suffixMax[i] 表示下标 i对应的分组中,以 i开始的后缀最大值。
时间复杂度:O(n)
空间复杂度:O(n)

    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        vector<int> prefixMax(n), suffixMax(n);
        for (int i = 0; i < n; ++i) {
            if (i % k == 0) {prefixMax[i] = nums[i];}
            else {prefixMax[i] = max(prefixMax[i - 1], nums[i]);}
        }
        for (int i = n - 1; i >= 0; --i) {
            if (i == n - 1 || (i + 1) % k == 0) {suffixMax[i] = nums[i];}
            else {suffixMax[i] = max(suffixMax[i + 1], nums[i]);}
        }
        vector<int> ans;
        for (int i = 0; i <= n - k; ++i) {
            ans.push_back(max(suffixMax[i], prefixMax[i + k - 1]));
        }
        return ans;
    }

效率有点低,花了一个晚上就整了这一道题,也算是全部搞清楚了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值