239. 滑动窗口最大值

239. 滑动窗口最大值

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

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

思路

其实问题就是解决怎么在一个窗口内使用O(1)的时间寻找最大值,并且在滑动时,也就是添加一个数和去掉一个数时,也能在线性复杂度找出最大值。

单调队列

可以想到维护一个类似单调栈的数据结构,单调队列,队列内的数据严格单调递减,因此每次寻找最大值时就直接返回队头即可,满足O(1)时间复杂度,然后就是维护单调队列的进队和出队操作了,进队时,从队尾开始,令所有小于当前值的元素全部出队,直到碰到比它大的元素,这样就保证了队列内的数据严格单调递减了。
出队操作对应滑动窗口向前滑动时,需要从队列出一个元素,只需要考虑出的元素是否等于队头元素即可,因为如果不是队头元素,就证明不是最大值,已经被覆盖了。

代码

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        deque<int> d;
        int n = nums.size();
        vector<int> ans;
        for(int i = 0; i < n; i++) {
            //先进队k-1个元素
            if(i < k - 1) {
            	//保证单调递减
                while(!d.empty() && d.back() < nums[i]) {
                    d.pop_back();
                }
                d.push_back(nums[i]);
            }
            //进队第k个元素
            else {
                while(!d.empty() && d.back() < nums[i]) {
                    d.pop_back();
                }
                d.push_back(nums[i]);
                //开始取值
                ans.push_back(d.front());
                //删除滑动窗口第一个元素
                if(d.front() == nums[i - k + 1]) {
                    d.pop_front();
                }
            }
        }
        return ans;
    }
};

左右分块

可以将数组按照k分块,定义left_max[i]表示从块头开始到位置i的最大值,状态转移方程为left_max[i] = max(left_max[i - 1], num[i]),特别地,当i % k时,也就是块开始时,left_max[i] = num[i],方向是从左到右,定义right_max[j]表示从右边开始,块头到位置j的最大值,状态转移方程为right_max[j] = max(right_max[j + 1], num[j]),特别地,当j + 1 % k时,right_max[j] = num[j]。
然后,对于[i, i + k - 1]的窗口内,只需要考虑left_max[i - k + 1]和right_max[i]即可。

代码

class Solution {
public:
    vector<int> maxSlidingWindow(vector<int>& nums, int k) {
        int n = nums.size();
        if(n * k == 0) {
            return {};
        }
        if(k == 1) {
            return nums;
        }
        vector<int> left_max(n);
        vector<int> right_max(n);
        left_max[0] = nums[0];
        right_max[n - 1] = nums[n - 1];
        for(int i = 1; i < n; i++) {
            if(i % k == 0) {
                left_max[i] = nums[i];
            }
            else {
                left_max[i] = max(left_max[i - 1], nums[i]);
            }

            int j = n - i - 1;
            if((j + 1) % k == 0) {
                right_max[j] = nums[j];
            }
            else {
                right_max[j] = max(nums[j], right_max[j + 1]);
            }
        }

        vector<int> ans;
        for(int i = 0; i < n - k + 1; i++) {
            ans.push_back(left_max[i + k - 1] < right_max[i]? right_max[i] : left_max[i + k - 1]);
        }
        return ans;
    }
};
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断路器保护灵敏度校验整改及剩余电流监测试点应用站用交流系统断

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值