LeetCode---239.滑动窗口的最大值

最初想法(错误)

思想:使用单调栈+滑动窗口的方式,首先先初始化一个单调递增栈这个单调递增栈的大小为k,这样可以第一个窗口中的最大值,会位于当前单调递增栈的栈顶,可以直接记录进入最终返回的vector,然后开始进行滑动窗口,设置l,r两个变量记录窗口的左右边界,分别初始化为0和k-1。然后每次将l++,r++,比较加入的nums[r]与栈顶元素的关系。如果大于元素,则入栈,并且将nums[r]加入最终的vector,如果小于,则将当前栈顶元素加入最终vertor。

显然,在这种思路中我忽视了对于过期元素的处理(即不在当前窗口内的元素可能在栈顶出现的问题)

#include<iostream>
#include<vector>
#include<stack>

using namespace std;

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> ans;  // 最终返回的ans
        stack<int> st;   // 需要维护的单调递增栈
        // 初始话第一个单调递增栈
        st.push(nums[0]);
        for(int i=1;i<k;i++){
            if(nums[i]>nums[i-1]) st.push(nums[i]);
        }
        ans.push_back(st.top());
        int l=0,r=k-1;
        while(r<nums.size()){
            l++;r++;
            if(nums[r]>st.top()){
                st.push(nums[r]);
            }
            ans.push_back(st.top());
        }
        return ans;
    }

};

解法二:双端队列+滑动窗口

虽然上述解法出现错误,但主要是在栈对于过期元素的处理不方便上,于是,我考虑了使用双端队列来完成上述思路。申请一个双端队列,用于维护当前窗口,每次加入一个窗口元素时,都先去除掉队列中小于当前插入元素的元素,这样能够维护队列的单调性,保证最大元素一直在队头,当循环变量i到达k-1之后,每一次都需要对最终的返回vector进行插入双端队列的队头元素。但是要先检查对头元素是在当前窗口内的,所以我们最好在存储双端队列时,存入的时,该元素在数组中的索引。

#include<iostream>
#include<vector>
#include<deque>

using namespace std;

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        vector<int> ans;  // 最终返回的ans
        deque<int> dq;   // 需要维护的双端队列
        for(int i=0;i<nums.size();i++){
            // 判断当前对头元素是否属于当前窗口
            if(!dq.empty()&&dq.front()<i-k+1){
                dq.pop_front();
            }
            // 清理当前队中小于当前需要插入元素的元素
            while(!dq.empty()&&nums[dq.back()]<nums[i]){
                dq.pop_back();
            }
            // 插入当前元素至队尾
            dq.push_back(i);
            // 当窗口达到k时开始统计最终的ans
            if(i>=k-1){
                ans.push_back(nums[dq.front()]);
            }
        }


        return ans;
    }

};

时间:O(n*k)最坏,当队列为递减队列时

空间:O(k) 用于维护双端单调队列

官方解法:

1.优先队列+滑动窗口

由于优先队列默认使用大根堆的方式存储,所以每次只需要判断当前的对丁元素是否在窗口内即可,如果不在就出队,在的话,当前窗口的最大值就是队顶元素,其实本质上思路与我的思路类似,不过他选择了一种更加适合的数据结构,可见熟练掌握并运用stl的重要性。

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        priority_queue<pair<int, int>> q;
        for (int i = 0; i < k; ++i) {
            q.emplace(nums[i], i);
        }
        vector<int> ans = {q.top().first};
        for (int i = k; i < n; ++i) {
            q.emplace(nums[i], i);
            while (q.top().second <= i - k) {
                q.pop();
            }
            ans.push_back(q.top().first);
        }
        return ans;
    }
};

作者:力扣官方题解
链接:https://leetcode.cn/problems/sliding-window-maximum/solutions/543426/hua-dong-chuang-kou-zui-da-zhi-by-leetco-ki6m/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

时间:O(nlogn)

空间:O(n)

官方解二与我的解类似。

官方解三太妙了,没怎么看懂。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值